diff --git a/.binder/Dockerfile b/.binder/Dockerfile new file mode 100644 index 0000000000..840042b32f --- /dev/null +++ b/.binder/Dockerfile @@ -0,0 +1,31 @@ +# sogno/dpsim:dev is built by dpsim-git/packaging/Docker/Dockerfile.dev +ARG BASE_IMAGE=sogno/dpsim:dev + +FROM ${BASE_IMAGE} + +ARG NotebookApp.default_url +ARG ip +ARG port +ARG NB_USER=jovyan +ARG NB_UID=1000 +ENV USER=${NB_USER} +ENV NB_UID=${NB_UID} +ENV HOME=/home/${NB_USER} + +RUN adduser \ + --comment "Default user" \ + --uid ${NB_UID} \ + ${NB_USER} + +COPY . ${HOME}/dpsim +ENV PATH="${HOME}/.local/bin:${PATH}" + +RUN python3 -m pip install notebook jupyterlab jupyterhub +USER root +RUN chown -R ${NB_UID} ${HOME} +USER ${NB_USER} +RUN rm -rf ${HOME}/dpsim/build && mkdir ${HOME}/dpsim/build +WORKDIR ${HOME}/dpsim + +RUN python3 -m build --wheel +RUN python3 -m pip install ./dist/dpsim* diff --git a/.clang-format b/.clang-format index 5bf551f4dd..3d43be1f73 100644 --- a/.clang-format +++ b/.clang-format @@ -4,6 +4,4 @@ --- BasedOnStyle: LLVM -# Increase ColumnLimit to avoid breaking SPDX headers -ColumnLimit: 200 - +ReflowComments: false diff --git a/.github/workflows/build_nix.yaml b/.github/workflows/build_nix.yaml new file mode 100644 index 0000000000..47e1c7c4f5 --- /dev/null +++ b/.github/workflows/build_nix.yaml @@ -0,0 +1,33 @@ +name: Build with Nix + +on: + push: + branches: + - master + pull_request: + +## Build ## + +jobs: + build: + name: Build with Nix + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: Setup Nix cache + uses: cachix/cachix-action@v14 + with: + name: dpsim + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Build dpsim + run: nix build .#dpsim diff --git a/.github/workflows/build_test_linux_fedora.yaml b/.github/workflows/build_test_linux_fedora.yaml index 0aa745bd1f..516c848448 100644 --- a/.github/workflows/build_test_linux_fedora.yaml +++ b/.github/workflows/build_test_linux_fedora.yaml @@ -2,8 +2,9 @@ name: Build & Test Fedora on: push: + branches: + - master pull_request: - types: [opened, synchronize, reopened] ## Build ## @@ -30,7 +31,7 @@ jobs: - name: Configure CMake shell: bash working-directory: ${{ github.workspace }}/build - run: cmake -DCIM_VERSION=CGMES_2.4.15_16FEB2016 $GITHUB_WORKSPACE + run: cmake -DCIM_VERSION=CGMES_2.4.15_16FEB2016 -DCOVERAGE=ON $GITHUB_WORKSPACE - name: Build dpsimpy and test examples shell: bash @@ -112,7 +113,7 @@ jobs: - name: Install parallel testing shell: bash - run: pip install pytest-xdist + run: pip install pytest pytest-xdist pytest-cov nbformat nbconvert - name: Run pytest shell: bash @@ -121,7 +122,7 @@ jobs: PYTHONPATH: "${{ github.workspace }}/build" run: | cp -r python/src/dpsim build/ - pytest -v examples/Notebooks -n auto + pytest -n auto --cov --cov-branch --cov-report=xml examples/Notebooks/ - name: Archive notebook outputs uses: actions/upload-artifact@v4 @@ -129,6 +130,32 @@ jobs: name: pytest-output-${{ github.sha }} path: outputs/ + - name: Install lcov + run: sudo dnf install -y lcov + + - name: Generate lcov report + run: | + lcov --capture --directory . --output-file coverage.info --rc lcov_branch_coverage=1 --ignore-errors mismatch + lcov --remove coverage.info '/usr/*' --output-file coverage.cleaned.info + lcov --list coverage.cleaned.info + + - name: Upload coverage artifacts + uses: actions/upload-artifact@v4 + with: + name: coverage-fedora--${{ github.sha }} + path: | + build/coverage.info + build/coverage_report/ + build/**/*.gc* + ${{ github.workspace }}/src/**/*.cpp + + + - name: Upload coverage report + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: sogno-platform/dpsim + compare-notebook-results: name: Compare Notebook results runs-on: ubuntu-latest @@ -286,11 +313,8 @@ jobs: uses: ./.github/workflows/run_villas_example.yaml with: compose_file_path: examples/villas/docker-compose-tests - container_commands: | - docker exec dpsim-compose-dpsim-1 /bin/bash -c "pip install paho-mqtt" - docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "/dpsim-mqtt" -u wildcard -v& - docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-producer.py"& - docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt.py" + example_name: dpsim-mqtt + continue_on_error: true test-villas-examples-2: name: Run dpsim-mqtt-import-export VILLASnode example @@ -298,9 +322,8 @@ jobs: uses: ./.github/workflows/run_villas_example.yaml with: compose_file_path: examples/villas/docker-compose-tests - container_commands: | - docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "#" -u wildcard -v& - docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-import-export.py" + example_name: dpsim-mqtt-import-export + continue_on_error: true test-villas-examples-3: name: Run dpsim-mqtt-import-export-MIMO VILLASnode example @@ -308,10 +331,8 @@ jobs: uses: ./.github/workflows/run_villas_example.yaml with: compose_file_path: examples/villas/docker-compose-tests + example_name: dpsim-mqtt-import-export-mimo continue_on_error: true - container_commands: | - docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "#" -u wildcard -v& - docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-import-export-MIMO.py" test-villas-examples-4: name: Run dpsim-file VILLASnode example @@ -319,10 +340,8 @@ jobs: uses: ./.github/workflows/run_villas_example.yaml with: compose_file_path: examples/villas/docker-compose-tests + example_name: dpsim-file continue_on_error: true - container_commands: | - docker exec dpsim-compose-dpsim-1 /bin/bash -c "sleep 3 && tail -f /dpsim/logs/output.csv"& - docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-file.py" test-villas-examples-5: name: Run mqtt-cigre-mv-pf-profiles VILLASnode example @@ -330,6 +349,5 @@ jobs: uses: ./.github/workflows/run_villas_example.yaml with: compose_file_path: examples/villas/docker-compose-tests - container_commands: | - docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "#" -u wildcard -v& - docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py" + example_name: mqtt-cigre-mv-pf-profiles + continue_on_error: true diff --git a/.github/workflows/build_test_linux_fedora_minimal.yaml b/.github/workflows/build_test_linux_fedora_minimal.yaml index ed7bf5bc44..45ab47f097 100644 --- a/.github/workflows/build_test_linux_fedora_minimal.yaml +++ b/.github/workflows/build_test_linux_fedora_minimal.yaml @@ -2,8 +2,9 @@ name: Build & Test Fedora Minimal on: push: + branches: + - master pull_request: - types: [opened, synchronize, reopened] ## Build ## diff --git a/.github/workflows/build_test_linux_rocky.yaml b/.github/workflows/build_test_linux_rocky.yaml index a2bd68c134..1f97e9e2cb 100644 --- a/.github/workflows/build_test_linux_rocky.yaml +++ b/.github/workflows/build_test_linux_rocky.yaml @@ -2,8 +2,9 @@ name: Build & Test RockyLinux on: push: + branches: + - master pull_request: - types: [opened, synchronize, reopened] ## Build ## @@ -59,9 +60,9 @@ jobs: - name: Configure CMake shell: bash working-directory: ${{ github.workspace }}/build - run: cmake $GITHUB_WORKSPACE -DFETCH_SPDLOG=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DWITH_PYBIND=OFF + run: cmake $GITHUB_WORKSPACE -DFETCH_SPDLOG=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang - name: Build every target shell: bash working-directory: ${{ github.workspace }}/build - run: cmake --build . --parallel $(nproc) \ No newline at end of file + run: cmake --build . --parallel $(nproc) diff --git a/.github/workflows/build_test_linux_rocky_profiling.yaml b/.github/workflows/build_test_linux_rocky_profiling.yaml index 476a0151ae..c63ac3ec26 100644 --- a/.github/workflows/build_test_linux_rocky_profiling.yaml +++ b/.github/workflows/build_test_linux_rocky_profiling.yaml @@ -3,68 +3,64 @@ name: Build & Profile RockyLinux on: workflow_dispatch: -## Build ## - jobs: profiling: name: Build with Profiling options runs-on: ubuntu-latest container: sogno/dpsim:dev-rocky steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Create Build Environment - run: mkdir build + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive - - name: Cache build directory - uses: actions/cache@v4 - with: - path: ${{ github.workspace }}/build - key: build-cache-rocky-profiling-${{ github.ref }} + - name: Create Build Environment + run: mkdir build - - name: Configure CMake - shell: bash - working-directory: ${{ github.workspace }}/build - run: cmake $GITHUB_WORKSPACE -DWITH_PROFILING=ON -DWITH_ASAN=ON -DWITH_CUDA=OFF -DFETCH_SPDLOG=ON + - name: Cache build directory + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/build + key: build-cache-rocky-profiling-${{ github.ref }} - - name: Build every target - shell: bash - working-directory: ${{ github.workspace }}/build - run: cmake --build . --parallel $(nproc) + - name: Configure CMake + shell: bash + working-directory: ${{ github.workspace }}/build + run: cmake $GITHUB_WORKSPACE -DWITH_PROFILING=ON -DWITH_ASAN=ON -DWITH_CUDA=OFF -DFETCH_SPDLOG=ON + - name: Build every target + shell: bash + working-directory: ${{ github.workspace }}/build + run: cmake --build . --parallel $(nproc) -## Tests ## test-examples-1: - name: Test Examples 1/4 + name: Test Examples 1/4 - WSCC_9bus_mult_coupled needs: [profiling] - uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@${{github.ref}} + uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@main with: - path: ./build/dpsim/examples/cxx/WSCC_9bus_mult_decoupled - name: WSCC_9bus_mult_decoupled + path: ./build/dpsim/examples/cxx/WSCC_9bus_mult_coupled + name: WSCC_9bus_mult_coupled test-examples-2: - name: Test Examples 2/4 + name: Test Examples 2/4 - WSCC_9bus_mult_decoupled needs: [profiling] - uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@${{github.ref}} + uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@main with: - path: ./build/dpsim/examples/cxx/WSCC_9bus_mult_coupled - name: WSCC_9bus_mult_coupled + path: ./build/dpsim/examples/cxx/WSCC_9bus_mult_decoupled + name: WSCC_9bus_mult_decoupled test-examples-3: - name: Test Examples 3/4 + name: Test Examples 3/4 - EMT_WSCC_9bus_split_decoupled needs: [profiling] - uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@${{github.ref}} + uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@main with: path: ./build/dpsim/examples/cxx/EMT_WSCC_9bus_split_decoupled - name: WSCC_9bus_split_decoupled + name: EMT_WSCC_9bus_split_decoupled test-examples-4: - name: Test Examples 4/4 + name: Test Examples 4/4 - DP_WSCC_9bus_split_decoupled needs: [profiling] - uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@${{github.ref}} + uses: sogno-platform/dpsim/.github/workflows/run_and_profile_example.yaml@main with: path: ./build/dpsim/examples/cxx/DP_WSCC_9bus_split_decoupled - name: WSCC_9bus_split_decoupled + name: DP_WSCC_9bus_split_decoupled diff --git a/.github/workflows/build_test_windows.yaml b/.github/workflows/build_test_windows.yaml index 6414822163..8771e82386 100644 --- a/.github/workflows/build_test_windows.yaml +++ b/.github/workflows/build_test_windows.yaml @@ -2,8 +2,9 @@ name: Build & Test Windows on: push: + branches: + - master pull_request: - types: [opened, synchronize, reopened] ## Build ## @@ -31,5 +32,6 @@ jobs: cd ${{ github.workspace }} cd build git describe --tags --abbrev=0 --match "v*" - cmake -DWITH_PYBIND=OFF .. + # TODO: Remove '-DCMAKE_POLICY_VERSION_MINIMUM=3.5' once spdlog version has been bumped + cmake -DWITH_PYBIND=OFF -DCMAKE_POLICY_VERSION_MINIMUM="3.5" .. cmake --build . --target dpsim --parallel diff --git a/.github/workflows/container.yaml b/.github/workflows/container.yaml index befcd30a23..5e3343b983 100644 --- a/.github/workflows/container.yaml +++ b/.github/workflows/container.yaml @@ -25,6 +25,7 @@ jobs: tags: sogno/dpsim:dev-rocky create-docker-fedora-release: + needs: create-docker-fedora-dev runs-on: ubuntu-latest steps: - name: Checkout @@ -104,3 +105,23 @@ jobs: push: true tags: sogno/dpsim:manylinux + create-docker-binder: + needs: create-docker-fedora-dev + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_SECRET }} + + - name: Build and push + id: docker_build_release + uses: docker/build-push-action@v5 + with: + file: .binder/Dockerfile + push: true + tags: sogno/dpsim:binder diff --git a/.github/workflows/documentation-fein.yaml b/.github/workflows/documentation-fein.yaml index 414fd285c3..f3fdec69fd 100644 --- a/.github/workflows/documentation-fein.yaml +++ b/.github/workflows/documentation-fein.yaml @@ -5,7 +5,7 @@ on: branches: - master -jobs: +jobs: deploy: runs-on: ubuntu-latest steps: @@ -36,7 +36,7 @@ jobs: - name: Deploy dpsim-simulator / FEIN uses: peaceiris/actions-gh-pages@v4 with: - deploy_key: ${{ secrets.HUGO_ACTIONS_DEPLOY_KEY }} + deploy_key: ${{ secrets.HUGO_ACTIONS_DEPLOY_KEY }} external_repository: dpsim-simulator/dpsim-simulator.github.io publish_dir: ./docs/hugo/public # keep_files: true diff --git a/.github/workflows/pre_commit.yaml b/.github/workflows/pre_commit.yaml new file mode 100644 index 0000000000..a5a8222c80 --- /dev/null +++ b/.github/workflows/pre_commit.yaml @@ -0,0 +1,14 @@ +name: Run pre-commit + +on: + pull_request: + push: + branches: [main] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/publish_to_pypi.yaml b/.github/workflows/publish_to_pypi.yaml index 86c8fbf1f3..9503a201b2 100644 --- a/.github/workflows/publish_to_pypi.yaml +++ b/.github/workflows/publish_to_pypi.yaml @@ -1,6 +1,7 @@ -name: Publish dpsim package to PyPi +name: Publish DPsim package to Python Package Index (PyPI) on: + pull_request: push: branches: - master @@ -8,9 +9,9 @@ on: - '*' jobs: - build-and-publish-sdist: - name: Build dpsim sdist and publish to PyPi - runs-on: ubuntu-latest + build-sdist: + name: Build DPsim source distribution + runs-on: ubuntu-24.04 container: sogno/dpsim:dev steps: - name: Checkout @@ -18,51 +19,84 @@ jobs: with: submodules: recursive - - name: Build dpsim source dist + - name: Build DPsim source distribution shell: bash run: python3 -m build --sdist --outdir dist/ - - name: Publish distribution to Test PyPI - uses: pypa/gh-action-pypi-publish@release/v1.8 + - name: Archive Python source distribution + uses: actions/upload-artifact@v4 with: - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - skip_existing: true - - - name: Publish distribution to PyPI - if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@release/v1.8 - with: - password: ${{ secrets.PYPI_API_TOKEN }} - + name: dist-source + path: dist/ - build-and-publish-wheels: - name: Build dpsim wheels and publish to PyPi - runs-on: ubuntu-20.04 + build-wheels: + name: Build DPsim Python wheel + runs-on: ubuntu-24.04 + strategy: + matrix: + platform: [manylinux_x86_64] + python: [cp39, cp310, cp311, cp312, cp313] steps: - name: Checkout uses: actions/checkout@v4 with: submodules: recursive - # - name: Build manylinux docker image # Remove this step as soon as the image is published on docker hub - # shell: bash - # run: docker build . --file packaging/Docker/Dockerfile.manylinux -t sogno/dpsim:manylinux - - - name: Build dpsim wheels for all supported python versions - uses: pypa/cibuildwheel@v2.18.0 + - name: Build wheel + uses: pypa/cibuildwheel@v2.23.2 + env: + CIBW_BUILD: "${{ matrix.python }}-${{ matrix.platform }}" + CIBW_MANYLINUX_X86_64_IMAGE: sogno/dpsim:manylinux with: output-dir: dist + - name: Upload wheel as artifact + uses: actions/upload-artifact@v4 + with: + name: dist-wheels-${{ matrix.python }}-${{ matrix.platform }} + path: dist/ + + publish-testpypi: + name: Publish wheels and source distribution to Test PyPI + runs-on: ubuntu-24.04 + if: github.event_name == 'push' + permissions: + id-token: write + needs: + - build-wheels + - build-sdist + + steps: + - name: Download wheels from build jobs + uses: actions/download-artifact@v4 + with: + pattern: dist-* + merge-multiple: true + path: dist/ + - name: Publish distribution to Test PyPI - uses: pypa/gh-action-pypi-publish@release/v1.8 + uses: pypa/gh-action-pypi-publish@v1.13.0 with: - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - skip_existing: true + repository-url: https://test.pypi.org/legacy/ + skip-existing: true - - name: Publish distribution to PyPI - if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@release/v1.8 + publish-pypi: + name: Publish wheels and source distribution to PyPI + runs-on: ubuntu-24.04 + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') && !contains(github.ref, '-rc') + permissions: + id-token: write + needs: + - build-wheels + - build-sdist + + steps: + - name: Download wheels from build jobs + uses: actions/download-artifact@v4 with: - password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file + pattern: dist-* + merge-multiple: true + path: dist/ + + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@v1.13.0 diff --git a/.github/workflows/run_and_profile_example.yaml b/.github/workflows/run_and_profile_example.yaml index d4058ce444..c24d8ab54f 100644 --- a/.github/workflows/run_and_profile_example.yaml +++ b/.github/workflows/run_and_profile_example.yaml @@ -12,37 +12,42 @@ on: required: true type: string - jobs: profiling-examples: name: Run example with profiling runs-on: ubuntu-latest container: sogno/dpsim:dev-rocky steps: - - name: Restore Cache - uses: actions/cache@v4 - with: - path: ${{ github.workspace }}/build - key: build-cache-rocky-profiling-${{ github.sha }} + - name: Restore Cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/build + key: build-cache-rocky-profiling-${{ github.sha }} + + - name: Run Binary + env: + BINARY_PATH: ${{ inputs.path }} + run: | + "$BINARY_PATH" 2>&1 | tee output.log + + - name: Extract metrics + shell: bash + working-directory: ${{ github.workspace }} + run: | + cat output.log | + sed -n -E -e 's/^.*Average step time. ([0-9]+\.[0-9]+)$/step-time \1/p' | + tee -a metrics.txt - - name: Run Binary - run: ${{ inputs.path }} 2>&1 | tee output.log - - - name: Extract metrics - shell: bash - working-directory: ${{ github.workspace }} - run: | - cat output.log | - sed -n -E -e 's/^.*Average step time. ([0-9]+\.[0-9]+)$/step-time \1/p' | - tee -a metrics.txt - - - name: Run Profiler - run: gprof ${{ inputs.path }} | gprof2dot -s | dot -Tpng -o profiling.png || true + - name: Run Profiler + env: + BINARY_PATH: ${{ inputs.path }} + run: | + gprof "$BINARY_PATH" | gprof2dot -s | dot -Tpng -o profiling.png || true - - name: Archive profiler output - uses: actions/upload-artifact@v4 - with: - name: profiler-output-${{ inputs.name }} - path: | - metrics.txt - profiling.png \ No newline at end of file + - name: Archive profiler output + uses: actions/upload-artifact@v4 + with: + name: profiler-output-${{ inputs.name }} + path: | + metrics.txt + profiling.png diff --git a/.github/workflows/run_villas_example.yaml b/.github/workflows/run_villas_example.yaml index 3a7891e0e0..363797262b 100644 --- a/.github/workflows/run_villas_example.yaml +++ b/.github/workflows/run_villas_example.yaml @@ -7,8 +7,8 @@ on: description: 'Path to the multi-container compose file' required: true type: string - container_commands: - description: 'docker exec commands for running tests in the containers' + example_name: + description: 'Which VILLAS example to run' required: true type: string continue_on_error: @@ -22,24 +22,64 @@ jobs: name: Run a VILLASnode example across multiple containers runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Restore build archive - uses: actions/download-artifact@v4 - with: - name: build-cache-examples-cpp-${{ github.sha }} - path: ${{ github.workspace }}/build - - - name: Start containers - run: cd ${{ inputs.compose_file_path }} && docker compose -p dpsim-compose up -d - - - name: Run container commands - timeout-minutes: 5 - continue-on-error: ${{ inputs.continue_on_error }} - shell: bash - run: ${{ inputs.container_commands }} - - - name: Stop containers - if: ${{ always() }} - run: cd ${{ inputs.compose_file_path }} && docker compose -p dpsim-compose down + - name: Checkout + uses: actions/checkout@v4 + + - name: Restore build archive + uses: actions/download-artifact@v4 + with: + name: build-cache-examples-cpp-${{ github.sha }} + path: ${{ github.workspace }}/build + + - name: Start containers + working-directory: ${{ inputs.compose_file_path }} + run: docker compose -p dpsim-compose up -d + + - name: Run VILLAS example container commands + timeout-minutes: 5 + continue-on-error: ${{ inputs.continue_on_error }} + shell: bash + env: + EXAMPLE_NAME: ${{ inputs.example_name }} + working-directory: ${{ github.workspace }} + run: | + set -e + + case "$EXAMPLE_NAME" in + dpsim-mqtt) + docker exec dpsim-compose-dpsim-1 /bin/bash -c "pip install paho-mqtt" + docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "/dpsim-mqtt" -u wildcard -v & + docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-producer.py" & + docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt.py" + ;; + + dpsim-mqtt-import-export) + docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "#" -u wildcard -v & + docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-import-export.py" + ;; + + dpsim-mqtt-import-export-mimo) + docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "#" -u wildcard -v & + docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-import-export-MIMO.py" + ;; + + dpsim-file) + docker exec dpsim-compose-dpsim-1 /bin/bash -c "sleep 3 && tail -f /dpsim/logs/output.csv" & + docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-file.py" + ;; + + mqtt-cigre-mv-pf-profiles) + docker exec dpsim-compose-mqtt-1 mosquitto_sub -t "#" -u wildcard -v & + docker exec dpsim-compose-dpsim-1 /bin/bash -c "cd /dpsim && python3 /dpsim/examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py" + ;; + + *) + echo "Unknown EXAMPLE_NAME: $EXAMPLE_NAME" >&2 + exit 1 + ;; + esac + + - name: Stop containers + if: ${{ always() }} + working-directory: ${{ inputs.compose_file_path }} + run: docker compose -p dpsim-compose down diff --git a/.github/workflows/sonar_cloud.yaml b/.github/workflows/sonar_cloud.yaml index 2e2fdfeafd..f845e31404 100644 --- a/.github/workflows/sonar_cloud.yaml +++ b/.github/workflows/sonar_cloud.yaml @@ -1,68 +1,44 @@ name: Sonar Cloud Analysis + on: - # Trigger analysis when pushing in master or pull requests, and when creating - # a pull request. push: branches: - master - pull_request: - types: [opened, synchronize, reopened] + pull_request_target: jobs: sonarcloud: name: Prepare and run Sonar Scan runs-on: ubuntu-latest container: sogno/dpsim:dev - outputs: - skip: ${{ steps.check-token.outputs.skip }} # Output to indicate if the job was skipped env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory - steps: - - name: Check for SONAR_TOKEN - id: check_token - run: | - if [ -z "${{ secrets.SONAR_TOKEN }}" ]; then - echo "SONAR_TOKEN is not set. Skipping the job." - echo "::set-output name=skip::true" - else - echo "::set-output name=skip::false" - fi - - - name: Skip Job if Token is Missing - if: steps.check_token.outputs.skip == 'true' - run: | - echo "Skipping the SonarCloud analysis due to missing SONAR_TOKEN." - exit 0 + steps: - name: Fetch repository - if: steps.check_token.outputs.skip != 'true' uses: actions/checkout@v4 with: fetch-depth: 0 + ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} - name: Setup Node 20 - if: steps.check_token.outputs.skip != 'true' uses: actions/setup-node@v4 with: node-version: 20 - name: Install sonar-scanner and build-wrapper - if: steps.check_token.outputs.skip != 'true' - uses: sonarsource/sonarcloud-github-c-cpp@v2 + uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v6 - name: Create Build Folder - if: steps.check_token.outputs.skip != 'true' run: mkdir build - name: Setup build directory cache - if: steps.check_token.outputs.skip != 'true' uses: actions/cache@v4 with: path: ${{ github.workspace }}/build key: wrapper-dir-cache-${{ github.ref }} - name: Setup sonar cache - if: steps.check_token.outputs.skip != 'true' uses: actions/cache@v4 with: path: | @@ -71,21 +47,18 @@ jobs: key: sonar-cache-${{ github.ref }} - name: Configure CMake - if: steps.check_token.outputs.skip != 'true' shell: bash working-directory: ${{ github.workspace }}/build - run: | - cmake -DCIM_VERSION=CGMES_2.4.15_16FEB2016 $GITHUB_WORKSPACE + run: cmake -DCIM_VERSION=CGMES_2.4.15_16FEB2016 "$GITHUB_WORKSPACE" - name: Run build-wrapper - if: steps.check_token.outputs.skip != 'true' - run: | - build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build/ -j $(nproc) + run: build-wrapper-linux-x86-64 --out-dir "${{ env.BUILD_WRAPPER_OUT_DIR }}" cmake --build build/ -j "$(nproc)" - name: Run sonar-scanner - if: steps.check_token.outputs.skip != 'true' + uses: SonarSource/sonarqube-scan-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - sonar-scanner --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json + with: + args: > + --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 54e4a431c0..0000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,559 +0,0 @@ -variables: - GIT_STRATEGY: fetch - GIT_SUBMODULE_STRATEGY: recursive - - RSYNC_OPTS: --recursive --ignore-missing-args --chown ${DEPLOY_USER}:${DEPLOY_USER} - - DOCKER_IMAGE: sogno/dpsim - DOCKER_IMAGE_DEV: sogno/dpsim-dev - DOCKER_IMAGE_DEV_ROCKY: sogno/dpsim-dev-rocky - - MAKE_OPTS: -j16 # for HYPER buildbots - -stages: - - prepare - - build - - test - - generate -# - deploy - -# moved to github actions -#.docker-fedora-template: &docker-fedora-template -# stage: prepare -# image: docker:20.10 -# needs: [] -# script: -# - docker build -# --build-arg MAKE_OPTS=${MAKE_OPTS} -# --file packaging/Docker/Dockerfile.dev -# ${TAGS} -# ${BUILD_ARGS} . -# tags: -# - docker -# -#docker:fedora-cgmes: -# <<: *docker-fedora-template -# variables: -# TAGS: --tag ${DOCKER_IMAGE_DEV}:${CI_COMMIT_REF_NAME}-cgmes --tag ${DOCKER_IMAGE_DEV}:latest -# BUILD_ARGS: --build-arg CIM_VERSION=CGMES_2.4.15_16FEB2016 - -# CGMES is the preferred CIM flavor -#docker:fedora-cim: -# <<: *docker-fedora-template -# variables: -# TAGS: --tag ${DOCKER_IMAGE_DEV}:${CI_COMMIT_REF_NAME}-cim -# BUILD_ARGS: --build-arg CIM_VERSION=IEC61970_16v29a - -docker:rocky: - stage: prepare - needs: [] - script: - - docker build . - --build-arg MAKE_OPTS=${MAKE_OPTS} - --file packaging/Docker/Dockerfile.dev-rocky - --tag ${DOCKER_IMAGE_DEV_ROCKY}:${CI_COMMIT_REF_NAME} - tags: - - docker - -# moved to github actions -#build:linux-cgmes: -# stage: build -# needs: ["docker:fedora-cgmes"] -# script: -# - mkdir -p build -# - cd build -# - cmake -DCIM_VERSION=CGMES_2.4.15_16FEB2016 .. -# - make -j 32 -# image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}-cgmes -# cache: -# artifacts: -# paths: -# - build -# tags: -# - docker - -# CGMES is the preferred CIM flavor -#build:linux-cim: -# stage: build -# needs: ["docker:fedora-cim"] -# script: -# - mkdir -p build -# - cd build -# - cmake -DCIM_VERSION=IEC61970_16v29a .. -# - make -j 32 -# image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}-cim -# cache: -# paths: -# - build -# key: build-linux -# tags: -# - docker - -# moved to github actions -#build:linux-profiling: -# stage: build -# needs: ["docker:centos"] -# script: -# - mkdir -p build -# - cd build -# - cmake -DWITH_PROFILING=ON -DWITH_ASAN=ON -DWITH_CUDA=OFF -DFETCH_SPDLOG=ON .. -# - make -j 32 -# image: ${DOCKER_IMAGE_DEV}-centos:${DOCKER_TAG} -# cache: -# artifacts: -# paths: -# - build -# tags: -# - docker - -build:linux-cuda: - stage: build - needs: ["docker:rocky"] - image: ${DOCKER_IMAGE_DEV_ROCKY}:${CI_COMMIT_REF_NAME} - artifacts: - paths: - - build - tags: - - docker - script: - - mkdir -p build - - cd build - - cmake -DWITH_CUDA=ON -DWITH_SPARSE=ON -DFETCH_SPDLOG=ON -DWITH_MAGMA=ON .. - - make ${MAKE_OPTS} - cache: - -# moved to GitHub actions -#build:windows: -# stage: build -# needs: [] -# script: -# - New-Item -ItemType Directory -Force -Path build -# - Set-Location -Path build -# - cmake .. -# - cmake --build . -j 24 - -# moved to GitHub actions -#build:docker: -# stage: build -# needs: [] -# script: -# - docker build -# --file packaging/Docker/Dockerfile -# --build-arg DOCKER_TAG=${DOCKER_TAG} -# --build-arg MAKE_OPTS=${MAKE_OPTS} -# --tag ${DOCKER_IMAGE}:${DOCKER_TAG} -# --tag ${DOCKER_IMAGE}:latest . -# tags: -# - docker -# only: -# - tags - -#build:macos: -# stage: build -# script: -# - mkdir -p build -# - cd build -# - cmake -DCMAKE_C_COMPILER=/usr/local/bin/gcc-9 -# -DCMAKE_CXX_COMPILER=/usr/local/bin/g++-9 -# -DFETCH_CIMPP=ON -# -DWITH_SUNDIALS=OFF .. -# - make -j $(sysctl -n hw.ncpu) -# cache: -# paths: -# - build -# key: build-macos -# artifacts: -# paths: -# - build -# tags: -# - mac - -#test:pytest: -# stage: test -# variables: -# PYTHONPATH: "build/Source/Python:Source/Python" -# script: -# - pytest -v examples/CIM/test_CIM.yml -# image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG} -# dependencies: -# - build:linux -# tags: -# - docker - -############################################################################## -# Stage test -############################################################################## - -# moved to GitHub actions -#test:jupyter-cgmes: -# stage: test -# needs: ["build:linux-cgmes"] -# variables: -# PYTHONPATH: "build:build/Source/Python:Source/Python" -# script: -# - pytest -v examples/Notebooks -# dependencies: -# - build:linux-cgmes -# image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}-cgmes -# tags: -# - docker -# artifacts: -# paths: -# - outputs/examples/Notebooks/ -# -#test:cppcheck 1/2: -# stage: test -# needs: ["docker:centos"] -# script: -# - set -o pipefail -# - cppcheck --max-configs=32 -j 32 --error-exitcode=1 -q --std=c++11 -I Include/ -I models/Include/ Source/ examples/ models/Source/ | tee cppcheck-error.log -# image: ${DOCKER_IMAGE_DEV}-centos:${DOCKER_TAG} -# dependencies: -# - docker:centos -# tags: -# - docker -# artifacts: -# when: on_failure -# paths: -# - cppcheck-error.log -# expose_as: 'cppcheck-error' -# -#test:cppcheck 2/2: -# stage: test -# needs: ["docker:centos"] -# allow_failure: true -# script: -# - set -o pipefail -# - cppcheck --max-configs=32 -j 32 --error-exitcode=1 -q --enable=warning,performance,portability,information,missingInclude --std=c++11 -I Include/ -I models/Include/ Source/ examples/ models/Source/ | tee cppcheck-warn.log -# image: ${DOCKER_IMAGE_DEV}-centos:${DOCKER_TAG} -# dependencies: -# - docker:centos -# tags: -# - docker -# artifacts: -# when: on_failure -# paths: -# - cppcheck-warn.log -# expose_as: 'cppcheck-warn' -# -#.test-examples: -# stage: test -# needs: ["build:linux-profiling"] -# script: -# - $TEST_BINARY_PATH/$TEST_BINARY $TEST_PARAM 2>&1 | tee output.log -# - cat output.log | -# sed -n -E -e 's/^.*Average step time. ([0-9]+\.[0-9]+)$/step-time \1/p' | -# tee -a metrics.txt -# - gprof $TEST_BINARY_PATH/$TEST_BINARY | gprof2dot -s | dot -Tpng -o profiling.png || true -# image: ${DOCKER_IMAGE_DEV}-centos:${DOCKER_TAG} -# dependencies: -# - build:linux-profiling -# tags: -# - docker -# artifacts: -# reports: -# metrics: metrics.txt -# paths: -# - profiling.png -# expose_as: 'test-examples' -# -#test:examples 1/2: -# extends: .test-examples -# variables: -## Name of the test binary -# TEST_BINARY: 'WSCC_9bus_mult_decoupled' -## Path where the test binary is located -# TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -## Command line parameters for the test binary -# TEST_PARAM: '' -# -#test:examples 2/2: -# extends: .test-examples -# variables: -## Name of the test binary -# TEST_BINARY: 'WSCC_9bus_mult_coupled' -## Path where the test binary is located -# TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -## Command line parameters for the test binary -# TEST_PARAM: '' - - -.benchmark-script: &benchmark-script | - for ((copies=0;copies<=$TEST_NUM_COPIES;copies++)) - do - echo "Running with $copies copies" - $TEST_BINARY_PATH/$TEST_BINARY $TEST_PARAM -o copies=$copies 2>&1 | tee output.log - cat output.log | - sed -n -E -e 's/^.*Average step time. ([0-9]+\.[0-9]+)$/\1/p' | - tee -a ${METRICS_ID}-metrics.txt - done - -.benchmark-step-times: - stage: test - script: - - *benchmark-script - image: ${DOCKER_IMAGE_DEV_ROCKY}:${CI_COMMIT_REF_NAME} - tags: - - docker - -test:solver-benchmark 1/2: - extends: .benchmark-step-times - needs: ["build:linux-cuda"] - dependencies: - - build:linux-cuda - variables: -# Metrics-filename - METRICS_ID: 'cpu-dense' -# Name of the test binary - TEST_BINARY: 'WSCC_9bus_mult_coupled' -# Path where the test binary is located - TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -# Up to how many copies should be benchmarked (WSCC_9bus - Example) - TEST_NUM_COPIES: 6 - TEST_PARAM: "-U EigenDense" - artifacts: - reports: - metrics: cpu-dense-metrics.txt - paths: - - cpu-dense-metrics.txt - expose_as: 'step-times-benchmark' - - -test:solver-benchmark 2/2: - extends: .benchmark-step-times - needs: ["build:linux-cuda"] - dependencies: - - build:linux-cuda - variables: -# Metrics-filename - METRICS_ID: 'cpu-sparse' -# Name of the test binary - TEST_BINARY: 'WSCC_9bus_mult_coupled' -# Path where the test binary is located - TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -# Up to how many copies should be benchmarked (WSCC_9bus - Example) - TEST_NUM_COPIES: 6 - TEST_PARAM: "-U EigenSparse" - artifacts: - reports: - metrics: cpu-sparse-metrics.txt - paths: - - cpu-sparse-metrics.txt - expose_as: 'step-times-benchmark' - - -.gpu-init-script: &gpu-init-script | - mkdir ~/.ssh && - echo "-----BEGIN OPENSSH PRIVATE KEY-----" > ~/.ssh/id_rsa && - echo $SSH_PRIVATE | sed "s/\S\{64\}/&\n/g" >> ~/.ssh/id_rsa && - echo "-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_rsa && - echo $SSH_PUBLIC > ~/.ssh/id_rsa.pub && - echo $KNOWN_HOSTS > ~/.ssh/known_hosts && chmod 600 ~/.ssh/id_rsa - echo "$TEST_BINARY_PATH/$TEST_BINARY $TEST_FILES" | tr -d '\n' | xargs -r -d " " -I % cp % $LDIR - ldd $LDIR/$TEST_BINARY | - sed -n -E -e 's/^\s+\S+ => (\S+) \S+$/\1/p' | - grep -Ev "$(echo $REMOTE_LIBS | tr ' ' '|')|not" | - xargs -I % cp % $LDIR/ - ssh $GPU_TARGET mkdir -p $RDIR - scp -r $LDIR/* $GPU_TARGET:$RDIR/ - -.gpu-run-script: &gpu-run-script | - ssh $GPU_TARGET "LD_LIBRARY_PATH=$RDIR:${LD_LIBRARY_PATH} LD_PRELOAD=$RDIR/cricket-server.so $RDIR/$TEST_BINARY" & - sleep 2 - PATH=$LDIR:${PATH} REMOTE_GPU_ADDRESS=ghost.acs-lab.eonerc.rwth-aachen.de LD_PRELOAD=$LDIR/cricket-client.so $TEST_BINARY_PATH/$TEST_BINARY $TEST_PARAM 2>&1 | tee output.log - cat output.log | - sed -n -E -e 's/^.*Average step time. ([0-9]+\.[0-9]+)$/\1/p' | - tee -a ${METRICS_ID}-metrics.txt - -.remote-gpu: - stage: test - variables: - GPU_TARGET: 'gitlab-runner@ghost' - RDIR: '/tmp/gitlab-jobs/$CI_PROJECT_NAME/$CI_JOB_ID' - CI_DIR: '$CI_BUILDS_DIR/$CI_PROJECT_PATH' - LDIR: '/cricket/bin' - TEST_FILES: '' - TEST_PARAM: '' - REMOTE_LIBS: 'linux-vdso.so.1 - librt.so.1 - libdl.so.2 - libcudart.so.10.2 - libcusolver.so.10 - libstdc\+\+.so.6 - libm.so.6 - libgcc_s.so.1 - libc.so.6 - /lib64/ld-linux-x86-64.so.2 - libutil.so.1 - libpthread.so.0' - script: - - *gpu-init-script - - *gpu-run-script - after_script: - - ssh $GPU_TARGET rm -rf $RDIR - - ssh $GPU_TARGET pkill -fe -2 $RDIR/$TEST_BINARY - image: ${DOCKER_IMAGE_DEV_ROCKY}:${CI_COMMIT_REF_NAME} - tags: - - docker - -test:cuda 1/3: - extends: .remote-gpu - needs: ["build:linux-cuda"] - dependencies: - - build:linux-cuda - variables: -# Metrics-filename - METRICS_ID: 'cuda' -# Name of the test binary - TEST_BINARY: 'WSCC_9bus_mult_coupled' -# Path where the test binary is located - TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -# Additional files that are necessary to run the application on the GPU node - TEST_FILE: '' -# Command line parameters for the test binary - TEST_PARAM: "-U CUDADense" - artifacts: - reports: - metrics: cuda-metrics.txt - paths: - - cuda-metrics.txt - expose_as: 'step-times-benchmark' - -test:cuda 2/3: - extends: .remote-gpu - needs: ["build:linux-cuda"] - dependencies: - - build:linux-cuda - allow_failure: true - variables: -# Metrics-filename - METRICS_ID: 'cuda' -# Name of the test binary - TEST_BINARY: 'WSCC_9bus_mult_coupled' -# Path where the test binary is located - TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -# Additional files that are necessary to run the application on the GPU node - TEST_FILE: '' -# Command line parameters for the test binary - TEST_PARAM: '-U CUDASparse' - artifacts: - reports: - metrics: cuda-metrics.txt - paths: - - cuda-metrics.txt - expose_as: 'step-times-benchmark' - -test:cuda 3/3: - extends: .remote-gpu - needs: ["build:linux-cuda"] - allow_failure: true - dependencies: - - build:linux-cuda - variables: -# Metrics-filename - METRICS_ID: 'cuda' -# Name of the test binary - TEST_BINARY: 'WSCC_9bus_mult_coupled' -# Path where the test binary is located - TEST_BINARY_PATH: 'build/dpsim/examples/cxx' -# Additional files that are necessary to run the application on the GPU node - TEST_FILE: '' -# Command line parameters for the test binary - TEST_PARAM: '-U CUDAMagma' - artifacts: - reports: - metrics: cuda-metrics.txt - paths: - - cuda-metrics.txt - expose_as: 'step-times-benchmark' - - -############################################################################## -# Stage generate -############################################################################## - -# moved to GitHub actions -#generate:docs: -# stage: generate -# needs: ["build:linux-cgmes"] -# script: -# - make ${MAKE_OPTS} -C build docs -# - make ${MAKE_OPTS} -C build docs_cxx -# image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}-cgmes -# dependencies: -# - build:linux-cgmes -# artifacts: -# paths: -# - build/docs/sphinx/html -# - build/docs/doxygen/html -# tags: -# - docker -# -#generate:packages: -# stage: generate -# needs: ["build:linux-cgmes"] -# script: -# - make ${MAKE_OPTS} -C build package -# only: -# - tags -# tags: -# - docker -# image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}-cgmes -# dependencies: -# - build:linux-cgmes -# artifacts: -# paths: -# - build/*.rpm -# - build/*.tar.gz - -generate:metrics: - stage: generate - needs: ["test:solver-benchmark 1/2", "test:solver-benchmark 2/2"] - script: - - echo "set terminal svg size 800, 500; set output 'metrics.svg'; set title 'Speed of different Solver-Configurations'; set style data lines; set key outside; set xlabel \"Copies (WSCC-9bus Example)\"; set ylabel \"Average steptime (µs)\"; set xtics 1; set xtics nomirror; set ytics nomirror; set grid; plot \"cpu-dense-metrics.txt\" using (\$1 * 1000000) title \"Solving with CPU and dense matrices\", \"gpu-dense-metrics.txt\" using (\$1 * 1000000) title \"Solving with GPU and dense matrices\", \"cpu-sparse-metrics.txt\" using (\$1 * 1000000) title \"Solving with CPU and sparse matrices\"" > script.p - - gnuplot script.p - image: ${DOCKER_IMAGE_DEV_ROCKY}:${CI_COMMIT_REF_NAME} - artifacts: - reports: - metrics: metrics.svg - paths: - - metrics.svg - expose_as: 'WSCC-9bus-benchmark' - tags: - - docker - - -############################################################################## -# Stage deploy -############################################################################## - -# moved to GitHub actions -#pages: -# stage: deploy -# needs: ["generate:docs"] -# script: -# - cp -r build/docs/sphinx/html/. public/sphinx -# - cp -r build/docs/doxygen/html/. public/doxygen -# artifacts: -# paths: -# - public -# dependencies: -# - generate:docs -# only: -# - deploy -# tags: -# - docker -# -#deploy:docker: -# stage: deploy -# script: -# - docker push ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}-cgmes -# - docker push ${DOCKER_IMAGE_DEV}:latest -# - docker push ${DOCKER_IMAGE}:${DOCKER_TAG}-cgmes -# - docker push ${DOCKER_IMAGE}:latest -# dependencies: -# - build:docker -# tags: -# - docker -# only: -# - tags diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..2163547fc3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + exclude: \.svg$ + - id: check-ast + - id: check-xml + - id: check-yaml + - id: check-json + # devcontainer.json contains comments + exclude: .devcontainer/devcontainer\.json + - id: check-toml + - id: check-added-large-files + - id: pretty-format-json + # black has its own mind of formatting Jupyter notebooks + exclude: \.ipynb$|^.devcontainer/devcontainer\.json$|package-lock\.json$ + args: + - --no-sort-keys + - --autofix + + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: "v17.0.6" + hooks: + - id: clang-format + files: \.(c|cpp|h|hpp)(\.in)?$ + args: [] + + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python + rev: "2.7.3" + hooks: + - id: editorconfig-checker + alias: ec + args: [-disable-indent-size] + + # Using this mirror lets us use mypyc-compiled black, which is about 2x faster + - repo: https://github.com/psf/black-pre-commit-mirror + rev: "25.11.0" + hooks: + - id: black + - id: black-jupyter + + - repo: https://github.com/markdownlint/markdownlint + rev: "v0.13.0" + hooks: + - id: markdownlint + args: [-r, "~MD013,~MD033,~MD024"] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..ff4a265e0d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,447 @@ +# Changelog + +All notable changes to this project will be documented in this file. +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/). + +## [v1.2.1] - 2025-12-10 + +Note: this version only includes a fix to the publishing workflow. See v1.2.0 for relevant changes since the last v1.1.1 + +### Fixed + +- TestPyPI and PyPI were part of the same job, solved a mixup/reuse of attestations (#459) + +## [v1.2.0] - 2025-12-10 + +### Added + +- Added this CHANGELOG.md file to track changes in the project. +- Adapt DPsim to deploy it in Mybinder (#323), moving Dockerfile to new .binder folder and adding job for building the binder Dockerfile. +- Add Code Coverage Report (#395), adding codecove badge and updating yaml file for code coverage. +- Add CODEOWNERS (#290) +- Add pre-commit (#352, #361, #363, #377, #382, #383, #385, #386) to harmonize code +- feat(cmake): Add install target (#381) +- New queueless VILLAS interface / improve real-time performance (#316), creating DCGenerator in VoltageSource only if special setParameters is used and not always when the frequency is 0 (avoiding regressions), and adding DP_PH1_ProfileVoltageSource used for the villas / fpga interface. +- Reuse conductance stamp code (#306), adding functions in MNAStampUtils for stamping value as a scalar matrix. +- Supress a warning treated as an error in MSVC (#280) +- update contact details (#254), updating contact details. +- Add support for CMake `find_package` and rename "KLU" dependency to name of actual library "SuiteSparse" (#380) +- Addition of EMT::Ph1::Switch component (#312), adding test notebook for VS_SW_RL1 circuit in EMT, DP and SP and fixing initialization. +- Linear SSN (#175), making EMT::Ph3 CurrentSource and SSN Full_Serial_RLC usable in pybind with implementation and declaration adjustments for EMT Ph3 CurrentSource. +- Implement decoupling line emt ph3 (#422), improving nine bus decoupling example with 3ph decoupling line and adding test for decoupling line Ph3 to Line.ipynb example. +- VILLASfpga cosimulation development (#325), adding n-eiling as codeowner of /dpsim-villas and fixing MNASolver to start loggers for vectors. +- Villas Interface: Improve FpgaExample (#299), allowing different topologies to be tested and updating VILLAS_VERSION in Dockerfile. +- Nix packaging (#357), adding GitHub CI workflow for building DPsim with Nix and Nix packaging. +- chore: update docs on real-time and VILLASnode interfaces (#335) +- Add dpsimpyvillas module to the CMake targets and include it in the Python wheel, using the correct Python install dependencies (#449) + +### Changed + +- Change python to python3 to run the building for pypi (#272) +- Disable code coverage in linux-fedora-examples on workflow (#412) +- editorconfig: set C++ indentation size to two (#295), setting it twice. +- Move pytest.ini to pyproject.toml (#348) +- Reduce attributes number (#388), declaring nominal/base voltages as Real instead of Attribute. +- Replace CentOS badge with RockyLinux badge (#282) +- villas: Use Python dictionaries for defining VILLASconfig files (#343) +- Change default linear solver to KLU (#250), fixing logging statements by using macros and removing explicit choice of SparseLU from cxx examples. +- Update WSCC_9bus_mult examples and implement splitting examples in DP and EMT (#322), removing SP_Ph1_CurrentSource component and fixing path to CIM files in decoupling line diakoptics example. +- Upgrade Fedora dockerfiles to v42 (#387), fixing KLU Adapter varying entry index check and adding libre to Dockerfile to fix one of the real-time errors using villas. +- Add new action using the build wrapper from sonar directly (#296) +- Allow builds without nlohmann/json library (#362) +- feat(ci): Use trusted / OIDC publishing to PyPi.org (#375), only attempting upload to PyPi for pushes to master or tags. +- Fixes to documentation and README, adding extra details about installation methods, contribution guidelines and how to try DPsim (#457). +- Update documentation and packaging metadata contact information, add CONTRIBUTORS file and GitHub Discussions link, and improve contributor/community guidance (#429, #413). +- Extend the changelog to include entries for older release versions and previously unreleased changes (#430). +- Use the DPsim manylinux container for building the Python package and skip RC versions when publishing to PyPI.org, while still publishing RC versions to TestPyPI (#451). + +### Removed + +- Remove commented out code (#390) +- Remove further RWTH gitlab dependencies (#261) +- Remove Python versions 3.6 and 3.7 for PyPi upload (#229) +- Disable test actions for PRs (#237) +- chore(cmake): Remove deprecated options (#342) +- Remove outdated and broken GitLab CI pipeline (#347) + +### Fixed + +- 5th Order Synchronous Generator (#230), fixing some minor details and adding SG5Order to CIM Reader in DP and EMT domain. +- Adding correct logger usage (#411) +- dpsim-villas: fix hardcoded paths (#327) +- Enable compilation in gcc 14 and clang 18 (code fixes) (#294) +- feat(cmake): Allow disable LTO builds (#341), adding WITH_MARCH_NATIVE option to enable native host arch builds. +- Fix consistency of calculations at first time step (#210), using Ph3 RMS quantities for initialSingleVoltage in EMT domain and adding macro DOUBLE_EPSILON. +- Fix docu issues (#310), substituting duplicate ODESolver with DAESolver in dpsim_classes_simulation.svg. +- Fix docu pipeline (#333) +- Fix initialization rxload (#241), fixing current initialization of EMT RXLoad. +- Fix module dpsimvillas (#401), fixing ambiguous use of VoltageNorton->SetParameters and fixing examples for realtime and CIM usage. +- Fix power flow initialisation of synchronous generators (#238), fixing pybind double definition of components_at_node and enforcing domain argument for initWithPowerflow. +- Fix rocky workflow due to changes in the profiling triggering (#305) +- Fix some capitalization (#351) +- Fix sonar scanner errors due to Java deprecated version (#265) +- Fix submodule initialization for CIMpp in Dockerfiles (#331), fixing it twice. +- Fix the profiling workflow (#399) +- Fix VILLASnode in Dockerfiles (#292), updating VILLASnode version in Dockerfile.manylinux and in other Dockerfiles. +- Fix workflow: option for parallel in make and error in publish to PyPI (#303) +- fix(cmake): Show feature summary even if not Git info is available (#379) +- fix: MNASolverPlugins examples (#346), fixing include paths of MNASolverPlugin examples and wrapping extern c in preprocessor condition. +- Fixes to the doxygen documentation INPUT line (#264) +- Fixing inconsistent switch attribute names in Base::Ph1::Switch and Base::Ph3::Switch (#418) +- Fixup whitespaces (#350) +- Hotfix: missing simulation stop (#247), adding missing stop function in the Simulation using pybind. +- pybind: Errors when compiling with clang (#334), fixing rocky container and updating villas version, fixing fedora container error in mosquito install and updating villas version. +- Reuse code for MNA matrix stamp operations (#297), logging stamping in MNAStampUtils and reusing admittance stamping logic for SP R,L,C components. +- Reuse stamp code for EMT synchron. generators (#315), adding matrix stamp functions with optimized logic in MNAStampUtils and fixing stamping of full matrix. +- Revision of power flow solver (#284), fixing PFSolver and minimizing file changes. +- Trigger actions for PRs and pin the version of libcimpp (#329), pinning libcimpp version in containers and cmake and triggering relevant workflows on pull_request event. +- Update actions in workflow and improve parallelisation and cache handling (#298), changing the profiling execution to manually triggered and enabling parallelisation with reorganized cache. +- Bump braces from 3.0.2 to 3.0.3 in /docs/hugo (#304) +- Bump postcss from 8.4.20 to 8.4.31 in /docs/hugo (#281) +- Bump version of black & black jupyter to 25.11.0 (#421) +- Bump yaml from 2.1.3 to 2.2.2 in /docs/hugo (#215) +- fix clang compilation and FPGA integration (#293), fixing clang compiler errors and adding clang compilation to CI. +- Fix CMake typos and style (#376) +- Fix GitHub actions workflow for publishing to PyPi (#355), building with newer CMake versions and simplifying triggers for workflows. +- Fix realtime datalogger (#400), adding example notebook for tests and pybind bindings. +- fix std::max behaviour in simulation.cpp for windows build using CMake (#408), fixing issue where windows.h breaks standard C++ behaviour of std::max. +- Fix the villas examples workflow (#319), adding supplementary cache and testing cache deletion. +- Fix Windows and Rocky/Clang builds (#360), fixing Windows builds with newer CMake versions. +- fix(ci): Attempt to fix PyPi package publish (#353) +- fix(ci): Fix tag of pypa/gh-action-pypi-publish action (#354), fixing the tag twice. +- fix(cmake): Fix code-style (#356) +- fix(deps): Add support for newer Spdlog versions (#340), adding missing #pragma once. +- fix(docs): Fix typo and wrong diff (#337) +- fix(examples): Only build Fpga9BusHil example if build with CIMpp (#338), applying it twice. +- fix(style): Remove duplicated typedef (#339) +- python: Harmonize comment style (#349) +- chore(deps): Bump pypa/gh-action-pypi-publish from 1.12.4 to 1.13.0 in /.github/workflows (#405) +- Update villas version (#245), updating python command to python3 in test-villas-examples actions and removing libwebsockets installation from source. +- Use clang-format to format the whole codebase (#278), fixing missing includes and moving development scripts from configs/ to scripts./ +- chore (deps): update to CIMpp rpm/deb install + bump VILLAS (#404), updating cmake fetch and finding of libcimpp and fixing dependent files and CIMReader. +- fix: Cleanup code-style of setup.py (#336) +- Reactivate VILLAS support in the MyBinder Python packaging workflow and fix related compilation issues when using dpsimpy with VILLAS-enabled containers (#450, #434, resolves #445). +- Create a symlink in the manylinux image to the install path of the OpenDSS C library to fix Python packaging and runtime loading issues (#448). +- Link DPsim to VILLAS libraries via CMake to fix missing linkage in VILLAS-enabled builds and examples (#447). +- Make the Fedora release workflow wait for the dpsim-dev container build to avoid race conditions in the release pipeline (#446). +- Security fix for the profiling workflow, avoiding passing commands as inputs to scripts in the profiling job (#455). +- Security fix for the VILLAS workflow, preventing commands from being passed as raw inputs into the shell (#454). +- Adapt the Sonar workflow to avoid deprecated secret checks so that scans still run for pull requests from forks (#456). +- Fix the Sonar workflow by bumping the action to the supported v6 version and adjusting configuration (#439). + +## [v1.1.1] - 2023-07-13 + +### Added + +- Add latest publications to website (#161) +- Introduce a common subclass for composite components (#177), adding comments for empty method implementations and renaming systemMatrixStamp methods for sparse matrices. +- Build and push RockyLinux image (#148) +- Update and expand documentation (#159), adding documentation on MNASimPowerComp and subcomponent handling. +- Introduce common base class MNASimPowerComp (#178), fixing merge errors and addressing SonarCloud issues. + +### Changed + +- Unify subcomponent handling and call MNA methods through the parent (#141) +- Move documentation to main repo (#154), adding hugo website files and moving content from dpsim-docs repo. +- Refactoring of direct linear solvers in MNA solver (#171), addressing further pull request comments and adding fetching of minimized suitesparse. + +### Fixed + +- Configurable linear solver (#199), addressing further pull request comments and processing default configuration options. +- Fix EMT_Ph1_Inductor initialization (#134), using Modelica results for validation and adding current validation in example VS_RL1. +- fix hugo website deployment (#158) +- Fix missing 'this' in logger macros (#217) +- Fix network frequency modulations and vsi snubber comps (#218), fixing some logging issues and trafo instantiation in dp and sp vsi for proper snubber comps. +- Fix various issues related to attributes (#140), addressing SonarCloud code smells and moving method implementations into source files. +- Profiling based optimisation (#194), addressing pull request comments and applying switched component stamps. +- Resolve FIXME comments (#142), addressing SonarCloud issues and renaming mMechPower attribute. +- Cleanup of CMake and Docker files (#168), adding missing libcimpp dependency for cimviz and comment explaining CMAKE_POLICY_DEFAULT_CMP0077. +- Deploy docs to FEIN website (#160), fixing repo url and subdir. +- fix and update documentation (#165), updating Contribution Guidelines and Roadmap. +- Fix implementation of exciter, new turbine governor model and refactor VBR models (#120), applying minor fixes and replacing validation notebook of reduced order SG models. +- Reduced-order syngen models (#213), removing unused variable in MNASolverDirect and unused methods/variables of MNASyncGenInterface. + +## [v1.1.0] - 2022-12-09 + +### Added + +- Add a basic VS Code devcontainer configuration +- add cppcheck for use in github actions, updating Dockerfile and install shell scripts and adding docker-compose for dpsim-mqtt examples. +- Add cps files to dpsim repo +- add deployment to gitlab pages +- add missing file headers, updating copyright year to 2021. +- Add new working mqtt example +- add notebook checking powerflow of ieee lv, adding notebook checking powerflow for cigre mv. +- add pillow dependencies to centos dockerfile +- add powerflow cim example +- add villas import example, using PQ attributes in SP load. +- add vsi model and examples +- allow vd, pv and pq comp at the same bus, setting bus type to vd, updating submodule grid-data and updating syngen model in sp1ph. +- avoid deadlock, adding log prefix and console logger for simulation and shmem interface. +- docker: add entry page to docker image, copying examples into image and starting Jupyter Lab by default. +- made all power components set parametersSet flag, adding setParameters flag and function with new constructor. +- python: add missing Compontents (closes #118) +- require only cmake 3.11 and make policies requiring a newer version optional +- shmem: update Python examples, allowing exporting of attributes with name & unit. +- sphinx: add sections in reference +- update cps, only declaring node templates in cpp for win and adding description type to setup.py. +- update steady state init and add logging + +### Changed + +- cmake dependent opt causes problem with cim +- cmake: use cmake_dependent_option() to avoid caching issues +- Create vnodes in pcomps instead of MNA solver and differentiate between 1ph and 3ph for the simNode assignment. +- flush spdlog after sim initialization, switching case for python log level and adding function to get current voltage. +- force gcc 11 in manylinux image +- initialize frequencies in SystemTopology +- Merge branch 'development' into 'master' +- Merge branch 'master' into multisampling, updating notebooks and gitignore. +- Merge branch 'patch-1' into 'master' +- Merge pull request #60 from JTS22/python-spdlog +- MNASolver: Increase maximum switch number to theoretical limit +- move libcps to models +- notebooks: clear results +- run autodoc on python submodules +- run page deploy on dedicated branch +- silence experimental fs visual studio warning +- started working on developer documentation +- Trigger PyPi-Workflow for tags (#151) +- update 9bus parallel notebook +- update cps, updating shmem distributed direct nb and shmem direct examples. +- update file headers and replace gpl with mpl in most files +- update inverter notebooks +- update shmem example of cigre mv +- update submodules path, updating dpsim results path in notebooks. +- rename Terminal, renaming TopologicalComponent and Node class. +- disable cim and render if deps not available, removing obsolete cim reader includes and working around github permission issue. +- update ci, restructuring sphinx doxygen docs and removing notebook related sphinx cmake. +- update cps, merging master and restructuring notebooks. +- update docs url +- update global scope of SynGenTrStab examples, adding Events category to examples and splitting examples in two categories: components & grids. +- update install script and new dockerfile, updating docker dev and using libxml instead of libexpat in cimpp. +- update shmem examples, using new cpp export methods in python interface and adding jupyter requirements file to docker fs. +- updated installation instructions, showing cmake invocation during setup.py and allowing setting CMake options via envvar. +- use correct minimum cmake version (3.13 instead of 3.12) because Policy CMP0076 requires 3.13, using different cache key for build with and without cuda and making CI build with CUDA support with CUDA dependencies in Dockerfile.dev. +- use updated dpsim-villas and villas-node versions, removing pipeline build caches and updating fedora and pybind versions. + +### Deprecated + +- moving old examples into villas-deprecated folder. + +### Removed + +- disable macos build +- harmonize namespace aliases of std::filesystem, removing useless printing of working directory in examples. + +### Fixed + +- add sst model and fix powerflow +- append .git to all module urls, fixing path to cim grid data and updating README. +- examples: fix notebook bin path, considering load "P" attribute in PF during simulation. +- fix brief class descriptions of reduced-order vbr models, fixing sp shift and adding grid voltage evaluations in validation notebooks, fixing cmd options after rebase. +- fix cim path for shmem example of cigre mv +- fix cmake policy warning +- fix dp ph3 voltagesource stamp +- Fix dpsim-villas version tag, using new villas version. +- fix GPLv3 logo (closes #125) +- fix load profile generation for different time steps in cigre shmem example, fixing cim files path and extending CLI options. +- fix minimal dockerfile +- fix powerflow with load profiles and use csvreader instead of loadprofilereader +- fix rxload initialization +- fix sourcevec writing and update villas-dataprocessing +- fixing mechanical torque as attribute after rebasing, adding logging of indices of varying matrix entries for reduced order VBR models in DP and EMT and adding smib reduced order load step examples. +- Merge branch 'debug-msp-example', updating cps and adding notebook with CS RL1 circuit. +- merge master, updating cps and using cmake_dependent_option() to avoid caching issues. +- MNASolverFactory.h: Only use Plugin Solver if activated, adding *.so to .gitignore and making MNASolverPlugin optional and deactivated on windows. +- python: fix invalid return value for Node::setInitialVoltage() +- spdlog macros, fix simNode assignment of vnodes, set links to master branch +- switch shared library off to fix dpsim_python, updating editorconfig and adding numpy cmake option again. +- update cps, ignoring attributes if index is larger than length and updating 9bus ctrl shmem example. +- update cps, fixing error in WSCC 9bus notebook and fixing feature notebooks. +- update readme, fixing shm python example and adding removed FindSphinx cmake file. +- update tlm comparison notebook, adding correct phase shift to transmission line and adding emt decoupling wave line model. +- use correct attribute dependency, making the phase changeable through mVoltageRef and using member variables for attribute access. +- use image for devcontainer, setting manual trigger for container workflow and fixing devcontainer.json. +- use initialization list for mZigZag, adding comments on voltage source behaviour and removing constructor for removing the SignalGenerator. +- add comments, adding another export to Simulation::sync and increasing timeout to allow dpsim to catch all mqtt messages. +- add link to build notebooks +- enable tests for pull requests, updating sonar settings and adding sonar cache and multithreading. +- examples: reduce sim time because of CI duration, fixing find pybind python in cmake. +- fix .gitlab-ci.yml to include correct path to rocky Dockerfile, fixing docker labels and removing duplicate needs statement. +- fix build badge +- fix doc gh-pages deployment +- fix emt ode syngen model, using systemtopolgy initFromPowerflow in examples and setting initFromNodes for MNA solver. +- fix file paths in notebook, updating notebook to use the new attribute system and exposing the entire attribute system to python. +- fix gitlab ci using old docker syntax (#147) +- Fix PyPi-Upload CI workflow (#149), finding Python3 instead of Python and updating container workflow actions. +- fix set pattern in scheduler, setting log pattern in scheduler and merging master. +- fix submodule build: throwing only warning when git version unavailable +- include Magma in Dockerfile, cleaning up gitlab-ci.yml, fixing GPUMagma inverse permutation bug and adding Magma based MNASolver. +- keep governor and exciter params separate from machine params, adding governor and exciter test examples for 9th order syngens and fixing exciter of dcim syngen. +- merge 1ph-refactoring, updating cps and fixing cpp 9 bus nb. +- Merge branch 'test-villas' into 'master', updating repo link in build docs and shmem example nb. +- Merge pull request #39 from stv0g/ci-minimal-build +- Merge pull request #46 from stv0g/ci-minimal-build +- minor tweaks to gitlab-ci +- move imports into cpp files, removing binary dir include for dpsimpy and clarifying Cpp version change. +- output dpsimpyvillas into top-level build directory, exporting complex attributes instead of matrices +- pybind: remove superfluous includes, removing unused VILLAS_VERSION variable from docker and allowing building examples without CIM support. +- re-enable notebook test, re-enabling example and adding missing test examples. +- reactivate continue_on_error parameter, adapting cigre mqtt example to run in pipeline and adding test for dpsim-mqtt-cigre example. +- refactor to store cli options as string +- remove cmake copy image, updating grid-data and examples with new grid data path. +- remove debug info from workflow, removing redundant jobs from gitlab and cleaning up dockerfiles. +- remove obsolete gitlab CI jobs, generating sphinx docs for new python interface. +- Revert :Fix compilation without libcimpp and minor tweaks to CMake code-style +- skip tests for old notebooks, adapting quickstart guide to dpsimpy and triggering actions on push to any branch. +- Use read-the-docs sphinx theme + +## [v1.0.0] - 2019-04-15 + +### Changed + +- Merge branch 'dae-solver-test' into 'development', adding documentation on real-time execution of DPsim (closes #108) and merging development into dae-solver-test. +- Merge branch 'gen-arkode' into 'development', updating Simulation.cpp and DataLogger.cpp. + +### Fixed + +- Continued to fix odeint example problem, adding example program for odeint based on DP_SynGen_dq_ThreePhFault of Arkode and first implementation of odeint solver class. +- Fixed initial value setting of odeint solver +- adaptations for DQ SynGen class split, merging branch 'development' into parallel and updating cps submodule. +- fixes for clang, adding parallel multimachine benchmark and fixing memleak in ODESolver. +- ifdef for sim_ode, updating .gitmodules and cps. +- include nbs in docs +- merge powerflow, applying minor logging fix in cigre mv powerflow test and writing config of data sent via villas. +- update cps, merging branch 'development' into powerflow-integration and updating dockerfile.dev. + +## [v0.1.6] - 2018-11-04 + +## [v0.1.5] - 2018-11-03 + +### Added + +- add missing _dpsim module to binary Python packages +- cmake: only integrate interface code if the platform supports it, adding more parameters to DPsim::RealTimeSimulation::run() and moving timer creation into {create,destroy}Timer(). +- docker: enable jupyter widgets +- python: add missing invocation of loggers to python simulation loop, adding proper reference counting for logged Components/Nodes. +- python: add missing progressbar package as dependency, pausing and resuming simulation asynchronously and adding more async events. +- update CPS submodule, providing synchronization settings per interface and making start script executable. +- updated cmake files for cimpp, including cimpp submodule in make files and adding libcimpp as submodule. +- updating cps, updating freq and load step example and removing NZ publication example. +- updating emt example, merging branch 'development' into msv-pra and updating examples. + +### Changed + +- flush data logs on simulation end, updating notebooks and raising error when dpsim.Simulation.run() is used with an already running event loop. +- Install expat dependency and execute setup +- Merge branch 'redesign_cimreader' into 'development' +- merge updated circuit examples, updating examples. +- python: do not fail load _dpsim.Interface (closes #93), reverting "comment out interface python class". +- python: separate EventChannel in header/source +- updated copyright year in C++ example +- merge changes into development, updating .gitlab-ci.yml and deactivating windows build until we have a runner again. +- merging changes in mna solver, using new DataLogger and making MNASolver not rely on CIM::Reader. +- merging changes into development, merging branch 'refactor-move-cps' into 'development' and not crashing if there are no CIM tests. +- merging new commits from development and node-terminal update, updating CPowerSystems submodule and refactoring Add{Excitor,Goveronor} -> add{Excitor,Goveronor}. +- Update Build.rst +- updating libcps, merging attribute test and merging redesign-simulation into development. +- shmem: libvillas-ext has been obsoleted by libvillas, simplifying dpsim.Simulation.run() and fixing error messages in CPS::Python::Component:getattro(). + +### Fixed + +- Adapted DAEsolver to new node/component structure and removed IDA dependency of Simulation file, making Residual function static and integrating DAE into Solver structure. +- docker: add Dockerfile for building a ready-to-run version of DPsim, fixing RPM dependencies and building RPM packages. +- docker: use fedora 29, fixing compilation without VILLASnode in python. +- fix DPsim logo in README.md +- fixing namespaces in simulation.cpp, updating CPS submodule for fixing linking errors and moving Python bindings for components to CPS. +- last buf fixes before merging, improving usage infos for command line args and adding missing header file. +- Merge branch 'development', changing shmem ids and increasing simulation time in wscc. +- python: fix logging of node voltages (closes #97) +- update CPS submodule, fixing attribute names in examples and python tests. +- fix windows build +- fixing CIM test yml, xfail for larger CIM example and removing TopologicalIsland from examples. +- Fixing parallel support of node indices and CIM, removing deprecated line load test and fixing network description without node objects. +- fixing segfault in mna solver when getting nodes, adding new examples and updating cps. +- Merge branch 'development', merging generator examples and updating cps. +- python: add some documentation to factory functions, fixing unit tests and changing NULL -> nullptr. +- tests: renamed python script in order to be selected by pytest, updating Python version of ShmemDistributedDirect test and refactoring examples for new lambda interface. + +## [v0.1.3] - 2018-02-21 + +### Changed + +- Update CMakeLists.txt +- refactor: DPsim::Components::Base -> DPsim::Component (closes #44), renaming "EMT_VoltageSourceNorton.{h, cpp}" to "EMT_VoltageSource_Norton.{h,cpp}" (see #43). + +### Fixed + +- fixed mistakes after merging, using SynGenSimulation for VBR simulation and integrating new DP VBR model with nodal analysis. +- Merge branch 'fix-transformer' into development merge, fixing CIM reader and example and applying minor changes in logging. +- examples: disable another failing CIM test, disabling broken IEEE-9-bus CIM test and refactoring mSeq -> mSequence. +- version bump, fixing url and image links in readme. + +## [v0.1.1] - 2018-01-12 + +### Added + +- added missing license and copyright headers (closes #23) +- TurbineGovernor: Added init function to initialize governor variables +- Update DP_ResVS_RXLine1.cpp, merging branch 'development' into 'shared-factory' and applying smaller cleanups. + +### Changed + +- do not use shared_ptrs for simulation Loggers +- Update .gitlab-ci.yml +- Update FaultSimulation.cpp, updating Simulation.cpp and merging branch 'development' into 'refactor-component-element-naming'. +- updated logdataline, fixing capitalization of filenames and excluding certain parts from Doxygen as they break Breathe. + +### Removed + +- refactor: rename namespace "DPsim::Component" -> "DPsim::Components", removing default constructor from components and naming base class files "Base_*.h". +- simulation: remove obsolete Generator test classes, simplifying expression and fixing real time simulation support in python. + +### Fixed + +- examples: fix hardcoded path (this is still ugly), installing libraries to correct location on Fedora and adding setup.py for installing / packaging with setuptools. +- fixed test builds +- Merge branch 'python-log' into 'development', fixing Python CI test and python ctor of Simulation class. + +## [v0.1.0] - 2017-12-26 + +### Added + +- changed newNode to node3, adding comments to header files of capacitor, ideal voltage source, inductor, inductor2 and voltSourceRes and adding documentation for ideal and real voltage source. +- created new components classes +- loglevel filter, updating study scripts and adding svg figures. +- Merge branch 'dev-vsa' into 'master', adding figures for synchronous machine and synchronous generator figure. +- Merge branch 'dev-vsa' into 'master', changing capacitor and inductor in simulation models and updating figure of inductor model. +- merge dev-mmi into master, documenting EMT DP comparison and first version of comparison between EMT and DP. +- moved Simulink models to other repo, adding folder DPsimReferenceExamples and deleting folder SimulinkExamples. +- Update LICENSE, adding license. +- VBR DP, merging branch 'development' and adding logo. +- Added omega_base to the equations of trapezoidal rule and implemented trapezoidal rule with current as state variable, implementing trapezoidal rule with flux as state for EMT and correcting mistake in equation of ifd. +- Created voltage behind reactance model - in construction, adding trapezoidal rule to DP synchronous generator and merging branch 'rt-exceptions' into development. + +### Changed + +- DP VBR working +- Merge branch 'development', merging master into dev-mmi merge and updating matlab scripts. +- Merge branch 'master' of git.rwth-aachen.de:PowerSystemSimulation/DPsim merge +- Update README.md +- VBR euler, adding matlab script to compare plecs with c++ results for synchronous generator and only compiling shmem/RT parts on Linux. +- VBR model - simulation of steady state +- adjust CMakeLists.txt, merging branch 'development' and merging branch 'cim-xml' into development. +- Merge branch 'dev-vsa' into 'master', updating LinearResistor.cpp and BaseComponent.h. + +### Removed + +- deleted vs project files, cmake works now in vs, adding vs folder to gitignore and deleting vs installation md file, updating build.rst. + +### Fixed + +- added GPLv3 headers to source files (closes #9), moving Source/Examples to Examples/ and treating unused variables as errors in Clang. +- Created Ideal Voltage Source EMT and fixed "virtual node", simplifying models with operational and fundamental parameters. +- fix compiler warnings (closes #15), creating simplified model of synchronous machine and making all generator models use SynchGenBase. +- implemented exciter and turbine to VBR DP model, fixing mistake in fault clearing function and adding Turbine Governor model. +- pass matrices via reference to silence compiler errors, adding Dockerfile and GitLab CI configuration and searching in standard location for Eigen. diff --git a/CMakeLists.txt b/CMakeLists.txt index 8801cbe8d5..e5022257a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Please keep 3.14 as minimum requirement for building on OPAL-RT targets cmake_minimum_required(VERSION 3.14...3.23) project(DPsim - VERSION 1.1.1 + VERSION 1.2.1 DESCRIPTION "C++ Power System Simulation Library" LANGUAGES CXX HOMEPAGE_URL "https://dpsim.fein-aachen.org/") @@ -12,6 +12,40 @@ set(PROJECT_DESCRIPTION "C++ Power System Simulation Library") set(PROJECT_HOMEPAGE_URL "https://dpsim.fein-aachen.org/") set(PROJECT_VCS_URL "https://github.com/sogno-platform/dpsim") +# Build options + +option(COVERAGE "Enable code coverage reporting" OFF) + +if(COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + message(STATUS "Enabling code coverage") + add_compile_options(--coverage -O0 -g) + add_link_options(--coverage) +endif() + +option(FETCH_EIGEN "Fetch Eigen3 as module" OFF) +option(FETCH_SUITESPARSE "Fetch SuiteSparse as module" ON) +option(FETCH_SPDLOG "Fetch spdlog as module" OFF) +option(FETCH_CIMPP "Fetch CIMpp as module" OFF) +option(FETCH_PYBIND "Fetch pybind11 as module" OFF) +option(FETCH_GRID_DATA "Fetch grid data" ON) +option(FETCH_FILESYSTEM "Fetch standalone implementation of std::filesystem" OFF) +option(FETCH_JSON "Fetch json library as module" ON) +option(FETCH_READERWRITERQUEUE "Fetch readerwriterqueue as module" ON) + +option(WITH_LTO "Enable Link Time Optimization in Release builds" OFF) +option(WITH_MARCH_NATIVE "Optimize build for native host architecture" OFF) +option(WITH_PROFILING "Add `-pg` profiling flag to compilation" OFF) +option(WITH_ASAN "Adds compiler flags to use the address sanitizer" OFF) +option(WITH_TSAN "Adds compiler flags to use the thread sanitizer" OFF) +option(WITH_SPARSE "Use sparse matrices in MNA-Solver" ON) + +option(BUILD_SHARED_LIBS "Build shared library" OFF) +option(DPSIM_BUILD_EXAMPLES "Build C++ examples" ON) +option(DPSIM_BUILD_DOC "Build documentation" ON) + +option(CGMES_BUILD "Build with CGMES instead of CIMpp" OFF) + + # Required for dpsim_python if(POLICY CMP0076) cmake_policy(SET CMP0076 NEW) @@ -27,16 +61,21 @@ if(WIN32) cmake_policy(SET CMP0074 NEW) endif() +# Define NOMINMAX to prevent Windows macros from breaking std::max +if(WIN32) + add_compile_definitions(NOMINMAX) +endif() + # Allow shadowing of CMake targets # As we include dependencies via add_subdirectory() # we import their targets into the DPsim CMake tree -# which might cause collissions in target names. +# which might cause collisions in target names. set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Select C++-Version # For the pybind11-python interface to compile, a minimum version of C++14 is required # If you need to compile using C++11, either disable the python interface or modify the source-files in Source/pybind, -# replacing all occurences of py::overload_cast with py::detail::overload_cast_impl as specified on +# replacing all occurrences of py::overload_cast with py::detail::overload_cast_impl as specified on # https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methods set(CMAKE_CXX_STANDARD 17) @@ -51,6 +90,7 @@ endif() set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") +include(GNUInstallDirs) include(CheckCXXCompilerFlag) if(MSVC) # Silence Visual Studio deprecation warnings @@ -79,43 +119,26 @@ include(CheckSymbolExists) check_symbol_exists(timerfd_create sys/timerfd.h HAVE_TIMERFD) check_symbol_exists(getopt_long getopt.h HAVE_GETOPT) if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - add_compile_options(-flto -march=native -Ofast) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Clang 18+ deprecates -Ofast; use the equivalent O3 instead. + add_compile_options(-O3) + else() + add_compile_options(-Ofast) + endif() + + if(WITH_MARCH_NATIVE) + add_compile_options(-march=native) + endif() + + if(WITH_LTO) + add_compile_options(-flto) + endif() endif() -# Get version info and buildid from Git +# Get version info and commit hash from Git include(GetVersion) GetVersion(${PROJECT_SOURCE_DIR} "DPSIM") -# Deprecated build options -# TODO: Remove deprecated options in future release -option(WITH_EIGEN_MODULE "Fetch Eigen3 as module (deprecated option)" OFF) -option(WITH_KLU "Build with KLU as module (deprecated option)" ON) -option(WITH_SPDLOG_SUBMODULE "Fetch spdlog as module (deprecated option)" OFF) -option(WITH_CIM_SUBMODULE "Fetch CIMpp as module (deprecated option)" OFF) -option(WITH_PYBIND_MODULE "Fetch pybind11 as module (deprecated option)" OFF) -option(GET_GRID_DATA "Fetch grid data (deprecated option)" ON) - -# Build options -option(FETCH_EIGEN "Fetch Eigen3 as module" ${WITH_EIGEN_MODULE}) -option(FETCH_KLU "Fetch KLU as module" ${WITH_KLU}) -option(FETCH_SPDLOG "Fetch spdlog as module" ${WITH_SPDLOG_SUBMODULE}) -option(FETCH_CIMPP "Fetch CIMpp as module" ${WITH_CIM_SUBMODULE}) -option(FETCH_PYBIND "Fetch pybind11 as module" ${WITH_PYBIND_MODULE}) -option(FETCH_GRID_DATA "Fetch grid data" ${GET_GRID_DATA}) -option(FETCH_FILESYSTEM "Fetch standalone implememtation of std::filesystem" OFF) - -option(WITH_JSON "Include json library" ON) -option(WITH_PROFILING "Add `-pg` profiling flag to compiliation" OFF) -option(WITH_ASAN "Adds compiler flags to use the address sanitizer" OFF) -option(WITH_TSAN "Adds compiler flags to use the thread sanitizer" OFF) -option(WITH_SPARSE "Use sparse matrices in MNA-Solver" ON) - -option(BUILD_SHARED_LIBS "Build shared library" OFF) -option(DPSIM_BUILD_EXAMPLES "Build C++ examples" ON) -option(DPSIM_BUILD_DOC "Build documentation" ON) - -option(CGMES_BUILD "Build with CGMES instead of CIMpp" OFF) - find_package(Threads REQUIRED) find_package(Sundials) find_package(OpenMP) @@ -138,15 +161,17 @@ else() find_package(Eigen3 3.0 REQUIRED) endif() -if (FETCH_KLU) - include(FetchKLU) +if(FETCH_SUITESPARSE) + include(FetchSuiteSparse) +else() + find_package(SuiteSparse 5.10) endif() if(FETCH_SPDLOG OR WIN32) include(FetchSpdlog) else() - find_package(spdlog 1.5.0 REQUIRED) - find_package(fmt 6.1.2 REQUIRED) + find_package(spdlog 1.10.0 REQUIRED) + find_package(fmt 8.1.1 REQUIRED) endif() if(FETCH_CIMPP OR WIN32) @@ -165,8 +190,16 @@ if(FETCH_GRID_DATA) include(FetchGridData) endif() -if(WITH_JSON) - include(FetchJsonLibrary) +if(FETCH_JSON) + include(FetchJson) +else() + find_package(nlohmann_json 3.9.1 REQUIRED) +endif() + +if(FETCH_READERWRITERQUEUE) + include(FetchReaderWriterQueue) +else() + find_package(readerwriterqueue 1.0.0 REQUIRED) endif() if(WITH_PROFILING) @@ -190,8 +223,6 @@ if(WITH_TSAN) endif() endif() -include(FetchReaderWriterQueue) - if("${CMAKE_SYSTEM}" MATCHES "Linux") set(Linux_FOUND ON) elseif("${CMAKE_SYSTEM}" MATCHES "Darwin") @@ -199,19 +230,22 @@ elseif("${CMAKE_SYSTEM}" MATCHES "Darwin") endif() include(CMakeDependentOption) -cmake_dependent_option(WITH_SUNDIALS "Enable sundials solver suite" ON "Sundials_FOUND" OFF) -cmake_dependent_option(WITH_VILLAS "Enable VILLASnode interface" ON "VILLASnode_FOUND" OFF) -cmake_dependent_option(WITH_RT "Enable real-time features" ON "Linux_FOUND" OFF) -cmake_dependent_option(WITH_CIM "Enable support for parsing CIM" ON "CIMpp_FOUND" OFF) -cmake_dependent_option(WITH_OPENMP "Enable OpenMP-based parallelisation" ON "OPENMP_FOUND" OFF) -cmake_dependent_option(WITH_CUDA "Enable CUDA-based parallelisation" OFF "CUDA_FOUND" OFF) -cmake_dependent_option(WITH_GRAPHVIZ "Enable Graphviz Graphs" ON "GRAPHVIZ_FOUND" OFF) -cmake_dependent_option(WITH_PYBIND "Enable PYBIND support" ON "pybind11_FOUND" OFF) -cmake_dependent_option(WITH_MAGMA "Enable MAGMA features" ON "MAGMA_FOUND" OFF) -cmake_dependent_option(WITH_MNASOLVERPLUGIN "Enable MNASolver Plugins" ON "NOT WIN32" OFF) +cmake_dependent_option(WITH_CIM "Enable support for parsing CIM" ON "CIMpp_FOUND" OFF) +cmake_dependent_option(WITH_CUDA "Enable CUDA-based parallelization" OFF "CUDA_FOUND" OFF) +cmake_dependent_option(WITH_GRAPHVIZ "Enable Graphviz Graphs" ON "GRAPHVIZ_FOUND" OFF) +cmake_dependent_option(WITH_GSL "Enable GSL features" ON "GSL_FOUND" OFF) +cmake_dependent_option(WITH_JSON "Enable JSON library support" ON "nlohmann_json_FOUND" OFF) +cmake_dependent_option(WITH_KLU "Enable KLU factorization" ON "SuiteSparse_FOUND" OFF) +cmake_dependent_option(WITH_MAGMA "Enable MAGMA features" ON "MAGMA_FOUND" OFF) +cmake_dependent_option(WITH_MNASOLVERPLUGIN "Enable MNASolver Plugins" ON "NOT WIN32" OFF) +cmake_dependent_option(WITH_OPENMP "Enable OpenMP-based parallelization" ON "OPENMP_FOUND" OFF) +cmake_dependent_option(WITH_PYBIND "Enable pybind support" ON "pybind11_FOUND" OFF) +cmake_dependent_option(WITH_RT "Enable real-time features" ON "Linux_FOUND" OFF) +cmake_dependent_option(WITH_SUNDIALS "Enable Sundials solver suite" ON "Sundials_FOUND" OFF) +cmake_dependent_option(WITH_VILLAS "Enable VILLASnode interface" ON "VILLASnode_FOUND" OFF) if(WITH_CUDA) - # BEGIN OF WORKAROUND - enable cuda dynamic linking. + # BEGIN OF WORKAROUND - enable CUDA dynamic linking. # Starting with Cmake 3.17 we can use # set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED") instead set(CMAKE_CUDA_FLAGS "" CACHE STRING "") @@ -223,7 +257,7 @@ if(WITH_CUDA) enable_language(CUDA) - # BEGIN OF WORKAROUND - enable cuda dynamic linking. + # BEGIN OF WORKAROUND - enable CUDA dynamic linking. if(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES) list(REMOVE_ITEM CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "cudart_static") list(REMOVE_ITEM CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "cudadevrt") @@ -241,17 +275,20 @@ if(WITH_CUDA) # END OF WORKAROUND endif() +if(WITH_PYBIND) + set(CMAKE_INSTALL_PYTHON_SITEPACKAGESDIR "${CMAKE_INSTALL_LIBDIR}/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages") +endif() + add_subdirectory(dpsim-models) +if(WITH_VILLAS) + add_subdirectory(dpsim-villas) +endif() add_subdirectory(dpsim) if(DPSIM_BUILD_DOC) add_subdirectory(docs) endif() -if(WITH_VILLAS) - add_subdirectory(dpsim-villas) -endif() - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") message(VERBOSE "Compiler Release Flags: " ${CMAKE_CXX_FLAGS_RELEASE}) message(VERBOSE "Compiler Debug Flags: " ${CMAKE_CXX_FLAGS_DEBUG}) @@ -259,26 +296,27 @@ endif() if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) include(FeatureSummary) - add_feature_info(CIM WITH_CIM "Loading Common Information Model (CIM) files") - add_feature_info(CUDA WITH_CUDA "CUDA-based parallelisation") + add_feature_info(CIM WITH_CIM "Common Information Model (CIM) support") + add_feature_info(CUDA WITH_CUDA "CUDA-based parallelization") add_feature_info(Graphviz WITH_GRAPHVIZ "Graphviz graphs") add_feature_info(GSL WITH_GSL "GNU Scientific library") - add_feature_info(JSON WITH_JSON "JSON library") + add_feature_info(JSON WITH_JSON "JSON parsing") + add_feature_info(KLU WITH_KLU "Use sparse KLU factorization") add_feature_info(MAGMA WITH_MAGMA "MAGMA features") add_feature_info(MNASolverPlugin WITH_MNASOLVERPLUGIN "MNASolver Plugins") - add_feature_info(OpenMP WITH_OPENMP "OpenMP-based parallelisation") - add_feature_info(PyBind WITH_PYBIND "PyBind module") + add_feature_info(OpenMP WITH_OPENMP "OpenMP-based parallelization") + add_feature_info(Pybind WITH_PYBIND "Python extension / bindings") add_feature_info(RealTime WITH_RT "Extended real-time features") add_feature_info(Sundials WITH_SUNDIALS "Sundials solvers") add_feature_info(VILLASnode WITH_VILLAS "Interface DPsim solvers via VILLASnode interfaces") - add_feature_info(KLU WITH_KLU "Use custom KLU module") feature_summary(WHAT ALL VAR enabledFeaturesText) + message(STATUS "Building ${CMAKE_PROJECT_NAME}:") + message(STATUS "Feature summary for DPsim") + message(STATUS "${enabledFeaturesText}") + if(FOUND_GIT_VERSION) - message(STATUS "Building ${CMAKE_PROJECT_NAME}:") - message(STATUS "Feature summary for DPsim") - message(STATUS "${enabledFeaturesText}") message(STATUS " VERSION: ${DPSIM_VERSION}") message(STATUS " RELEASE: ${DPSIM_RELEASE}") message(STATUS " GIT_REV: ${DPSIM_GIT_REV}") diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000000..5198bc84d6 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,41 @@ +# Contributors + +We would like to thank all contributors who have helped develop and improve DPsim over the years, whether through code, research, testing, or feedback. + +This list is based on deduplicated commit authors and highlights main contributors. +For a complete, automatically updated list use the command `git shortlog -sne`. + +## Main contributors + +- Markus Mirz +- Steffen Vogel +- Jonas Schroeder +- Jan Dinkelbach +- Georg Reinke +- Viviane Sapucaia +- Niklas Eiling +- Lennart Schumacher +- Junjie Zhang +- Martin Moraga +- Ghassen Nakti + +## Other contributors (alphabetical) + +- Anas Bahr +- Andrés Acosta +- Bettina Schäfer +- Christoph Wirtz +- Daniel Döhring +- Felix Wege +- Florian Oppermann +- Georgii Tishenin +- Henri Lubjuhn +- Leonardo Carreras +- Marvin Tollnitsch +- Petra Raussi +- Philipp Fensch +- Philipp Jungkamp +- Richard Marston +- Ruben Sander +- Shikhin Dah +- Stefan Lankes diff --git a/LICENSE b/LICENSE index fa0086a952..a612ad9813 100644 --- a/LICENSE +++ b/LICENSE @@ -370,4 +370,4 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. \ No newline at end of file + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index 34dfa37916..111dc1debb 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ # DPsim [![Build & Test RockyLinux](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_linux_rocky.yaml/badge.svg)](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_linux_rocky.yaml) - [![Build & Test Fedora](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_linux_fedora.yaml/badge.svg)](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_linux_fedora.yaml) - [![Build & Test Fedora Minimal](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_linux_fedora_minimal.yaml/badge.svg)](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_linux_fedora_minimal.yaml) - [![Build & Test Windows](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_windows.yaml/badge.svg)](https://github.com/sogno-platform/dpsim/actions/workflows/build_test_windows.yaml) [![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0) +[![codecov](https://codecov.io/gh/sogno-platform/dpsim/graph/badge.svg?token=FLUOQ8U7MH)](https://codecov.io/gh/sogno-platform/dpsim) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/4887/badge)](https://www.bestpractices.dev/projects/4887) DPsim is a solver library for dynamic power system simulation. @@ -20,6 +19,22 @@ DPsim is a solver library for dynamic power system simulation. - It can load models in the IEC61970 CIM / CGMES XML format. - It can be interfaced to a variety of protocols and interfaces via [VILLASnode](https://fein-aachen.org/projects/villas-node/). +## Getting started + +### Using Binder + +Click the badge below to explore the interactive Jupyter notebooks in your browser: + +[![Binder](https://2i2c.mybinder.org/badge_logo.svg)](https://2i2c.mybinder.org/v2/gh/sogno-platform/dpsim/HEAD?urlpath=%2Fdoc%2Ftree%2Fexamples%2FIndex.ipynb) + +### Using Python on Linux + +Install DPsim on Linux using the command + +```shell +pip install dpsim +``` + ## Documentation The [documentation](https://dpsim.fein-aachen.org/) has build / installation instructions, links to examples and explains the concepts implemented in DPsim as well as its architecture. @@ -28,11 +43,20 @@ The [documentation](https://dpsim.fein-aachen.org/) has build / installation ins The project is released under the terms of the [MPL 2.0](https://mozilla.org/MPL/2.0/). +For email inquiries regarding other licensing options, please contact the Institute for Automation of Complex Power Systems (ACS), which coordinates DPsim development: [post_acs@eonerc.rwth-aachen.de](mailto:post_acs@eonerc.rwth-aachen.de). + ## Contact -[LF Energy Slack](https://slack.lfenergy.org/) - Chat with other users and developers and get help in the **#sogno** or **#sogno-dpsim** channel. +[GitHub Discussions](https://github.com/sogno-platform/dpsim/discussions) - Ask questions, share ideas, and get community support. + +## Contribute + +If you want to get more involved with DPsim, we welcome contributions of all kinds, including code, documentation, examples, models, bug reports, feature requests, and reviews. + +Please open a Pull Request or issue on [GitHub](https://github.com/sogno-platform/dpsim), or start a discussion there to propose ideas and get feedback from the community. + +Have you developed something new and want to contribute it? Check the [documentation](https://dpsim.fein-aachen.org/) for details on the preferred way to organize your code contributions. + +## Contributors -You can also send a direct message to -- Markus Mirz -- Jan Dinkelbach -- Steffen Vogel +See [CONTRIBUTORS.md](https://github.com/sogno-platform/dpsim/blob/master/CONTRIBUTORS.md) for a list of contributors. diff --git a/cmake/DPsimPackaging.cmake b/cmake/DPsimPackaging.cmake index b202bcc6bb..1d2d6e3594 100644 --- a/cmake/DPsimPackaging.cmake +++ b/cmake/DPsimPackaging.cmake @@ -1,6 +1,6 @@ set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) set(CPACK_PACKAGE_VENDOR ${PROJECT_AUTHOR}) -set(CPACK_PACKAGE_CONTACT "Steffen Vogel ") set(CPACK_PACKAGE_VERSION ${DPSIM_SHORT_VERSION}) set(CPACK_PACKAGE_VERSION_MAJOR ${DPSIM_MAJOR_VERSION}) set(CPACK_PACKAGE_VERSION_MINOR ${DPSIM_MINOR_VERSION}) diff --git a/cmake/FetchCIMpp.cmake b/cmake/FetchCIMpp.cmake index dff0edce1e..e121aa0113 100644 --- a/cmake/FetchCIMpp.cmake +++ b/cmake/FetchCIMpp.cmake @@ -1,13 +1,26 @@ -if(NOT CIM_VERSION) +# cmake_minimum_required handled by your top-level CMakeLists +# Requires CMake >= 3.14 for FetchContent_MakeAvailable + +set(CIM_VERSION "${CIM_VERSION}" CACHE STRING "CIM version (e.g. CGMES_2.4.15_16FEB2016 or 16v29a)") +if(NOT CIM_VERSION OR CIM_VERSION STREQUAL "") set(CIM_VERSION "CGMES_2.4.15_16FEB2016") endif() -# Allow overriding the commit hash externally -if(NOT DEFINED CIMPP_COMMIT) - set(CIMPP_COMMIT "1b11d5c17bedf0ae042628b42ecb4e49df70b2f6") # Default commit +set(CIMPP_COMMIT "${CIMPP_COMMIT}" CACHE STRING "libcimpp git commit to fetch") +if(NOT DEFINED CIMPP_COMMIT OR CIMPP_COMMIT STREQUAL "") + if(WIN32) + # Windows builds currently rely on the older commit; update once validated there. + set(CIMPP_COMMIT "1b11d5c17bedf0ae042628b42ecb4e49df70b2f6") + else() + # Linux and other platforms use the newer known-good commit. + set(CIMPP_COMMIT "051ee4c311572fe92b30120b897d22deb253e162") + endif() endif() -message(STATUS "CIM Version: ${CIM_VERSION}") +message(STATUS "[CIMpp] CIM Version: ${CIM_VERSION}") +message(STATUS "[CIMpp] Commit: ${CIMPP_COMMIT}") + +set(CGMES_BUILD OFF) if(CIM_VERSION STREQUAL "16v29a") set(USE_CIM_VERSION "IEC61970_16v29a") @@ -16,15 +29,40 @@ elseif(CIM_VERSION STREQUAL "CGMES_2.4.15_16FEB2016") set(CGMES_BUILD ON) endif() -set(CIMPP_BUILD_DOC OFF) +set(CIM_VERSION "${CIM_VERSION}" CACHE STRING "" FORCE) +set(CGMES_BUILD "${CGMES_BUILD}" CACHE BOOL "" FORCE) +set(CIMPP_BUILD_DOC OFF CACHE BOOL "Build libcimpp docs (disabled)" FORCE) include(FetchContent) + FetchContent_Declare(cimpp-module GIT_REPOSITORY https://github.com/sogno-platform/libcimpp.git - GIT_PROGRESS TRUE GIT_TAG ${CIMPP_COMMIT} + GIT_PROGRESS TRUE ) FetchContent_MakeAvailable(cimpp-module) -set(CIMpp_FOUND TRUE) +set(_candidates CIMPP::cimpp cimpp libcimpp) +set(_cimpp_target "") +foreach(tgt IN LISTS _candidates) + if(TARGET ${tgt}) + set(_cimpp_target ${tgt}) + break() + endif() +endforeach() + +if(_cimpp_target STREQUAL "") + message(FATAL_ERROR "[CIMpp] Fetched libcimpp but no library target was found (checked: ${_candidates}).") +endif() + +if(NOT TARGET CIMPP::cimpp) + if(_cimpp_target STREQUAL "CIMPP::cimpp") + else() + add_library(CIMPP::cimpp ALIAS ${_cimpp_target}) + endif() +endif() + +set(CIMpp_FOUND TRUE CACHE BOOL "Fetched CIMpp successfully" FORCE) +set(CIMPP_CGMES_BUILD ${CGMES_BUILD} CACHE BOOL "Is this a CGMES build?" FORCE) +set(CIMPP_USE_VERSION "${USE_CIM_VERSION}" CACHE STRING "Resolved internal CIM version tag" FORCE) diff --git a/cmake/FetchJson.cmake b/cmake/FetchJson.cmake new file mode 100644 index 0000000000..9752bc9ee4 --- /dev/null +++ b/cmake/FetchJson.cmake @@ -0,0 +1,11 @@ +include(FetchContent) +FetchContent_Declare(json + GIT_REPOSITORY https://github.com/nlohmann/json + GIT_TAG v3.11.3 + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE +) + +FetchContent_MakeAvailable(json) + +set(nlohmann_json_FOUND ON) diff --git a/cmake/FetchJsonLibrary.cmake b/cmake/FetchJsonLibrary.cmake deleted file mode 100644 index 9b361ddcf7..0000000000 --- a/cmake/FetchJsonLibrary.cmake +++ /dev/null @@ -1,9 +0,0 @@ -include(FetchContent) -FetchContent_Declare(json-module - GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent - GIT_TAG v3.9.1 - GIT_SHALLOW TRUE - GIT_PROGRESS TRUE -) - -FetchContent_MakeAvailable(json-module) diff --git a/cmake/FetchReaderWriterQueue.cmake b/cmake/FetchReaderWriterQueue.cmake index 7fbd78e2c9..8d89131c90 100644 --- a/cmake/FetchReaderWriterQueue.cmake +++ b/cmake/FetchReaderWriterQueue.cmake @@ -7,3 +7,5 @@ FetchContent_Declare(readerwriterqueue-module ) FetchContent_MakeAvailable(readerwriterqueue-module) + +add_library(readerwriterqueue::readerwriterqueue ALIAS readerwriterqueue) diff --git a/cmake/FetchSpdlog.cmake b/cmake/FetchSpdlog.cmake index dd661f3c81..037f5075ff 100644 --- a/cmake/FetchSpdlog.cmake +++ b/cmake/FetchSpdlog.cmake @@ -5,7 +5,7 @@ option(SPDLOG_BUILD_EXAMPLES "Build spdlog examples" OFF) include(FetchContent) FetchContent_Declare(spdlog-module GIT_REPOSITORY https://github.com/gabime/spdlog.git - GIT_TAG v1.5.0 + GIT_TAG v1.15.0 GIT_SHALLOW TRUE GIT_PROGRESS TRUE ) diff --git a/cmake/FetchKLU.cmake b/cmake/FetchSuiteSparse.cmake similarity index 55% rename from cmake/FetchKLU.cmake rename to cmake/FetchSuiteSparse.cmake index d0719d6685..aaf1e257e9 100644 --- a/cmake/FetchKLU.cmake +++ b/cmake/FetchSuiteSparse.cmake @@ -1,8 +1,12 @@ include(FetchContent) FetchContent_Declare( - klu-module + suitesparse-module URL https://github.com/dpsim-simulator/SuiteSparse/releases/download/release-v5.10.6/SuiteSparse-release-v5.10.6.tar.gz ) -FetchContent_MakeAvailable(klu-module) +FetchContent_MakeAvailable(suitesparse-module) + +add_library(SuiteSparse::KLU ALIAS klu) + +set(SuiteSparse_FOUND ON) diff --git a/cmake/FindCIMpp.cmake b/cmake/FindCIMpp.cmake index b22b6115cc..dce5663751 100644 --- a/cmake/FindCIMpp.cmake +++ b/cmake/FindCIMpp.cmake @@ -1,48 +1,139 @@ -if(NOT CIM_VERSION) +cmake_minimum_required(VERSION 3.12) + +set(CIM_VERSION "${CIM_VERSION}" CACHE STRING "CIM version (e.g. CGMES_2.4.15_16FEB2016)") +set(CIMPP_ROOT "${CIMPP_ROOT}" CACHE PATH "CIMpp install prefix (/usr, /usr/local, /opt/cimpp)") + +if(NOT CIM_VERSION OR CIM_VERSION STREQUAL "") set(CIM_VERSION "CGMES_2.4.15_16FEB2016") + message(STATUS "[CIMpp] CIM_VERSION not provided, defaulting to ${CIM_VERSION}") +else() + message(STATUS "[CIMpp] CIM_VERSION provided: ${CIM_VERSION}") endif() -message(STATUS "CIM Version: ${CIM_VERSION}") - -if(CIM_VERSION STREQUAL "16v29a") - set(USE_CIM_VERSION "IEC61970_16v29a") +if(NOT CIMPP_ROOT OR CIMPP_ROOT STREQUAL "") + set(CIMPP_ROOT "/usr/local") + message(STATUS "[CIMpp] CIMPP_ROOT not provided, defaulting to ${CIMPP_ROOT}") +else() + message(STATUS "[CIMpp] CIMPP_ROOT provided: ${CIMPP_ROOT}") endif() -if(CIM_VERSION STREQUAL "CGMES_2.4.15_16FEB2016") - set(USE_CIM_VERSION "CGMES_2.4.15_16FEB2016") + +# Detect CGMES builds and expose a flag +set(CGMES_BUILD OFF) +if(CIM_VERSION MATCHES "^CGMES_") set(CGMES_BUILD ON) endif() -find_path(CIMPP_INCLUDE_DIR - NAMES CIMModel.hpp +# Hints +set(_hints ${CIMPP_ROOT} $ENV{CIMPP_ROOT} /usr /usr/local) +list(FILTER _hints EXCLUDE REGEX "^$") + +# version: .../include/cimpp/ +find_path(CIMPP_VER_INCLUDE_DIR + NAMES Line.hpp + HINTS ${_hints} PATH_SUFFIXES - cimpp/${CIM_VERSION} - ${CIM_VERSION} - cimpp/${USE_CIM_VERSION} - ${USE_CIM_VERSION} - include/src -) + include/cimpp/${CIM_VERSION} + include/cimpp) -find_library(CIMPP_LIBRARY - NAMES cimpp${CIM_VERSION} cimpp${USE_CIM_VERSION} +# src: .../include/cimpp/src +find_path(CIMPP_SRC_INCLUDE_DIR + NAMES CIMFile.hpp + HINTS ${_hints} + PATH_SUFFIXES + include/cimpp + include/cimpp/${CIM_VERSION} + include/cimpp/src + include/cimpp/${CIM_VERSION}/src) + +# static: .../include/cimpp/static +find_path(CIMPP_STATIC_INCLUDE_DIR + NAMES BaseClass.hpp + HINTS ${_hints} + PATH_SUFFIXES + include/cimpp/${CIM_VERSION} + include/cimpp/${CIM_VERSION}/static + include/cimpp/static + include/cimpp) + +# static/IEC61970: .../include/cimpp/static/IEC61970 +find_path(CIMPP_STATIC_IEC61970_INCLUDE_DIR + NAMES IEC61970CIMVersion.h + HINTS ${_hints} PATH_SUFFIXES - lib/static -) + include/cimpp/${CIM_VERSION}/IEC61970 + include/cimpp/${CIM_VERSION}/static/IEC61970 + include/cimpp/static/IEC61970 + include/cimpp/IEC61970) -set(CIMPP_LIBRARIES - ${CIMPP_LIBRARY} - ${ARABICA_LIBRARY} -) +# ---- Library (search specific directories only) +set(_cimpp_library_dirs "") +foreach(_root IN LISTS _hints) + if(_root) + list(APPEND _cimpp_library_dirs + "${_root}/lib" + "${_root}/lib64" + "${_root}/lib/x86_64-linux-gnu") + endif() +endforeach() +list(APPEND _cimpp_library_dirs "/lib" "/lib64" "/lib/x86_64-linux-gnu") +list(REMOVE_DUPLICATES _cimpp_library_dirs) -set(CIMPP_INCLUDE_DIRS - ${CIMPP_INCLUDE_DIR} - ${ARABICA_INCLUDE_DIR} -) +find_library(CIMPP_LIBRARY + NAMES cimpp${CIM_VERSION} cimppCGMES_2.4.15_16FEB2016 cimpp + PATHS ${_cimpp_library_dirs} + NO_DEFAULT_PATH) +# ---- Revalidate discovered paths (avoid cached empty or stale results) +macro(_cimpp_recheck _var) + if(${_var} AND NOT EXISTS "${${_var}}") + unset(${_var} CACHE) + set(${_var} "") + endif() +endmacro() + +_cimpp_recheck(CIMPP_SRC_INCLUDE_DIR) +_cimpp_recheck(CIMPP_VER_INCLUDE_DIR) +_cimpp_recheck(CIMPP_STATIC_INCLUDE_DIR) +_cimpp_recheck(CIMPP_STATIC_IEC61970_INCLUDE_DIR) +_cimpp_recheck(CIMPP_LIBRARY) + +# ---- Validate include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(CIMpp DEFAULT_MSG CIMPP_LIBRARY CIMPP_INCLUDE_DIR) +find_package_handle_standard_args(CIMpp + REQUIRED_VARS + CIMPP_LIBRARY + CIMPP_SRC_INCLUDE_DIR + CIMPP_VER_INCLUDE_DIR + CIMPP_STATIC_INCLUDE_DIR + CIMPP_STATIC_IEC61970_INCLUDE_DIR + FAIL_MESSAGE "Set CIMPP_ROOT and CIM_VERSION so that the include paths are found.") -mark_as_advanced(CIMPP_LIBRARY CIMPP_INCLUDE_DIR) +if(NOT TARGET CIMPP::cimpp) + add_library(CIMPP::cimpp UNKNOWN IMPORTED) + set(_incs + "${CIMPP_SRC_INCLUDE_DIR}" + "${CIMPP_VER_INCLUDE_DIR}" + "${CIMPP_STATIC_INCLUDE_DIR}" + "${CIMPP_STATIC_IEC61970_INCLUDE_DIR}") + foreach(_inc IN LISTS _incs) + if(_inc STREQUAL "" OR NOT EXISTS "${_inc}") + list(REMOVE_ITEM _incs "${_inc}") + endif() + endforeach() + list(REMOVE_DUPLICATES _incs) + if(NOT CIMPP_LIBRARY OR _incs STREQUAL "") + message(WARNING "[CIMpp] Skipping CIMPP::cimpp target because include paths or library are missing") + unset(CIMPP_LIBRARY CACHE) + set(CIMPP_LIBRARY "") + else() + set_target_properties(CIMPP::cimpp PROPERTIES + IMPORTED_LOCATION "${CIMPP_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${_incs}") + endif() +endif() -add_library(libcimpp INTERFACE) -target_link_libraries(libcimpp INTERFACE ${CIMPP_LIBRARIES}) -target_include_directories(libcimpp INTERFACE ${CIMPP_INCLUDE_DIRS}) +message(STATUS "[CIMpp] src = ${CIMPP_SRC_INCLUDE_DIR}") +message(STATUS "[CIMpp] version = ${CIMPP_VER_INCLUDE_DIR}") +message(STATUS "[CIMpp] static = ${CIMPP_STATIC_INCLUDE_DIR}") +message(STATUS "[CIMpp] IEC61970 = ${CIMPP_STATIC_IEC61970_INCLUDE_DIR}") +message(STATUS "[CIMpp] lib = ${CIMPP_LIBRARY}") diff --git a/cmake/FindGSL.cmake b/cmake/FindGSL.cmake index 90ae8c8f1c..c39567c7b7 100644 --- a/cmake/FindGSL.cmake +++ b/cmake/FindGSL.cmake @@ -1,4 +1,4 @@ -if (WIN32) +if(WIN32) # GSL is currently not supported for Windows else() find_path(GSL_INCLUDE_DIR diff --git a/cmake/FindSuiteSparse.cmake b/cmake/FindSuiteSparse.cmake new file mode 100644 index 0000000000..bef36448c7 --- /dev/null +++ b/cmake/FindSuiteSparse.cmake @@ -0,0 +1,35 @@ +find_path(SUITESPARSE_INCLUDE_DIR NAMES amd.h) +find_library(SUITESPARSE_AMD_LIBRARY NAMES amd) +find_library(SUITESPARSE_COLAMD_LIBRARY NAMES colamd) +find_library(SUITESPARSE_BTF_LIBRARY NAMES btf) +find_library(SUITESPARSE_KLU_LIBRARY NAMES klu) + +set(SUITESPARSE_LIBRARIES ${SUITESPARSE_AMD_LIBRARY} ${SUITESPARSE_COLAMD_LIBRARY} ${SUITESPARSE_BTF_LIBRARY} ${SUITESPARSE_KLU_LIBRARY}) +set(SUITESPARSE_INCLUDE_DIRS ${SUITESPARSE_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SuiteSparse DEFAULT_MSG SUITESPARSE_LIBRARIES SUITESPARSE_INCLUDE_DIR) + +mark_as_advanced(SUITESPARSE_INCLUDE_DIR SUITESPARSE_LIBRARIES) + +add_library(SuiteSparse::BTF STATIC IMPORTED) +set_property(TARGET SuiteSparse::BTF PROPERTY IMPORTED_LOCATION ${SUITESPARSE_BTF_LIBRARY}) +target_include_directories(SuiteSparse::BTF INTERFACE ${SUITESPARSE_INCLUDE_DIR}) + +add_library(SuiteSparse::COLAMD STATIC IMPORTED) +set_property(TARGET SuiteSparse::COLAMD PROPERTY IMPORTED_LOCATION ${SUITESPARSE_COLAMD_LIBRARY}) +target_include_directories(SuiteSparse::COLAMD INTERFACE ${SUITESPARSE_INCLUDE_DIR}) + +add_library(SuiteSparse::AMD STATIC IMPORTED) +set_property(TARGET SuiteSparse::AMD PROPERTY IMPORTED_LOCATION ${SUITESPARSE_AMD_LIBRARY}) +target_include_directories(SuiteSparse::AMD INTERFACE ${SUITESPARSE_INCLUDE_DIR}) + +add_library(SuiteSparse::KLU STATIC IMPORTED) +set_property(TARGET SuiteSparse::KLU PROPERTY IMPORTED_LOCATION ${SUITESPARSE_KLU_LIBRARY}) +target_include_directories(SuiteSparse::KLU INTERFACE ${SUITESPARSE_INCLUDE_DIR}) + +target_link_libraries(SuiteSparse::KLU INTERFACE + SuiteSparse::AMD + SuiteSparse::BTF + SuiteSparse::COLAMD +) diff --git a/cmake/FindSundials.cmake b/cmake/FindSundials.cmake index 5203badaf0..9c5756c412 100644 --- a/cmake/FindSundials.cmake +++ b/cmake/FindSundials.cmake @@ -1,4 +1,4 @@ -if (WIN32) +if(WIN32) message(STATUS "Sundials is currently not supported in Windows") else() find_path(SUNDIALS_INCLUDE_DIR @@ -42,5 +42,5 @@ else() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Sundials DEFAULT_MSG SUNDIALS_ARKODE_LIBRARY SUNDIALS_INCLUDE_DIR) - mark_as_advanced(SUNDIALS_INCLUDE_DIR) + mark_as_advanced(SUNDIALS_INCLUDE_DIR SUNDIALS_LIBRARIES) endif() diff --git a/cmake/FindVILLASnode.cmake b/cmake/FindVILLASnode.cmake index 0feeca4eaa..ce54fe9748 100644 --- a/cmake/FindVILLASnode.cmake +++ b/cmake/FindVILLASnode.cmake @@ -6,10 +6,36 @@ find_library(VILLASNODE_LIBRARY NAMES villas ) +find_library(VILLASCOMMON_LIBRARY + NAMES villas-common +) + +find_library(VILLASFPGA_LIBRARY + NAMES villas-fpga +) + set(VILLASNODE_LIBRARIES ${VILLASNODE_LIBRARY}) set(VILLASNODE_INCLUDE_DIRS ${VILLASNODE_INCLUDE_DIR}) +set(VILLASCOMMON_LIBRARIES ${VILLASCOMMON_LIBRARY}) +set(VILLASFPGA_LIBRARIES ${VILLASFPGA_LIBRARY}) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(VILLASnode DEFAULT_MSG VILLASNODE_LIBRARY VILLASNODE_INCLUDE_DIR) +find_package_handle_standard_args( + VILLASnode + DEFAULT_MSG + VILLASNODE_LIBRARY + VILLASNODE_INCLUDE_DIR + VILLASCOMMON_LIBRARY +) + +message(STATUS "VILLAS include: ${VILLASNODE_INCLUDE_DIR}") +message(STATUS "VILLASnode library: ${VILLASNODE_LIBRARY}") +message(STATUS "VILLAScommon library: ${VILLASCOMMON_LIBRARY}") +message(STATUS "VILLASfpga library: ${VILLASFPGA_LIBRARY}") -mark_as_advanced(VILLASNODE_INCLUDE_DIR VILLASNODE_LIBRARY) +mark_as_advanced( + VILLASNODE_INCLUDE_DIR + VILLASNODE_LIBRARY + VILLASCOMMON_LIBRARY + VILLASFPGA_LIBRARY +) diff --git a/configs/example_configs_json/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_SyngenParams.json b/configs/example_configs_json/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_SyngenParams.json index e87b22dcba..81947e416c 100644 --- a/configs/example_configs_json/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_SyngenParams.json +++ b/configs/example_configs_json/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_SyngenParams.json @@ -1,17 +1,17 @@ { - "name": "EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_JsonSyngenParams", - "options": { - "Rs" : 0.003, - "Ll" : 0.15, - "Ld" : 1.8099, - "Lq" : 1.7600, - "Ld_t" : 0.2999, - "Ld_s" : 0.2299, - "Lq_t" : 0.6500, - "Lq_s" : 0.2500, - "Td0_t" : 8.0669, - "Td0_s" : 0.0300, - "Tq0_t" : 0.9991, - "Tq0_s" : 0.0700 - } + "name": "EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_JsonSyngenParams", + "options": { + "Rs": 0.003, + "Ll": 0.15, + "Ld": 1.8099, + "Lq": 1.76, + "Ld_t": 0.2999, + "Ld_s": 0.2299, + "Lq_t": 0.65, + "Lq_s": 0.25, + "Td0_t": 8.0669, + "Td0_s": 0.03, + "Tq0_t": 0.9991, + "Tq0_s": 0.07 + } } diff --git a/configs/realtime_tests/decoupled.sh b/configs/realtime_tests/decoupled.sh index fbbe08561a..f219c9dfba 100755 --- a/configs/realtime_tests/decoupled.sh +++ b/configs/realtime_tests/decoupled.sh @@ -8,4 +8,4 @@ do sudo taskset --all-tasks --cpu-list 12-23 chrt --fifo 99 build/dpsim/examples/cxx/WSCC_9bus_mult_decoupled -ocopies=$i -othreads=$j -oseq=$k done done -done \ No newline at end of file +done diff --git a/configs/realtime_tests/diakoptics.sh b/configs/realtime_tests/diakoptics.sh index cba6a91c3f..801f9b223d 100755 --- a/configs/realtime_tests/diakoptics.sh +++ b/configs/realtime_tests/diakoptics.sh @@ -11,4 +11,4 @@ do done done done -done \ No newline at end of file +done diff --git a/configs/realtime_tests/inverter.sh b/configs/realtime_tests/inverter.sh index 4c767366b5..5b9b7d1c3e 100755 --- a/configs/realtime_tests/inverter.sh +++ b/configs/realtime_tests/inverter.sh @@ -13,4 +13,4 @@ do do sudo taskset --all-tasks --cpu-list 12-23 chrt --fifo 99 build/dpsim/examples/cxx/DP_Inverter_Grid_Parallel -othreads=$j -oseq=$k done -done \ No newline at end of file +done diff --git a/configs/shmem_cosim/shmem_test.conf b/configs/shmem_cosim/shmem_test.conf index d744fd1f3c..cf9546b090 100644 --- a/configs/shmem_cosim/shmem_test.conf +++ b/configs/shmem_cosim/shmem_test.conf @@ -9,7 +9,7 @@ "dpsim": { "path": "./", "scenario": { - "directory": "build/dpsim/examples/cxx/", + "directory": "build/dpsim-villas/examples/cxx/", "name": "ShmemDistributedVillas", "args": "1" }, @@ -19,13 +19,13 @@ "name": "sogno/dpsim:dev", "tag": "latest" }, - + "container_name": "shmem_tests" } }, "remote_sim":{ "path": "dpsim/", - "exec_command": "docker exec -w /dpsim shmem_tests ./build/dpsim/examples/cxx/ShmemDistributedVillas 0" + "exec_command": "docker exec -w /dpsim shmem_tests ./build/dpsim-villas/examples/cxx/ShmemDistributedVillas 0" } -} \ No newline at end of file +} diff --git a/configs/start_ShmemDistributedDirect.sh b/configs/start_ShmemDistributedDirect.sh index bfc1ae4ec8..911797037f 100644 --- a/configs/start_ShmemDistributedDirect.sh +++ b/configs/start_ShmemDistributedDirect.sh @@ -2,7 +2,7 @@ CPS_LOG_PREFIX="[Left ] " build/dpsim-villas/examples/cxx/ShmemDistributedDirect 0 & P1=$! CPS_LOG_PREFIX="[Right] " build/dpsim-villas/examples/cxx/ShmemDistributedDirect 1 & P2=$! - + for job in $P1 $P2; do wait $job || exit 1 -done \ No newline at end of file +done diff --git a/configs/start_ShmemExample.sh b/configs/start_ShmemExample.sh index cb5eab653f..26c60cda34 100755 --- a/configs/start_ShmemExample.sh +++ b/configs/start_ShmemExample.sh @@ -24,7 +24,7 @@ nodes = { ) } - exec = [ "build/dpsim/examples/cxx/ShmemExample" ] + exec = [ "build/dpsim-villas/examples/cxx/ShmemExample" ] } input = { diff --git a/docs/doxygen/CMakeLists.txt b/docs/doxygen/CMakeLists.txt index 4aa11c973f..a1d44e1a63 100644 --- a/docs/doxygen/CMakeLists.txt +++ b/docs/doxygen/CMakeLists.txt @@ -16,4 +16,9 @@ if(DOXYGEN_FOUND) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM ) + + install(DIRECTORY ${DOXYGEN_HTML_DIR} + DESTINATION ${CMAKE_INSTALL_DOCDIR}/doxygen + OPTIONAL + ) endif() diff --git a/docs/doxygen/DoxyMain.md b/docs/doxygen/DoxyMain.md index d1a43c1ed5..7c2e670f24 100644 --- a/docs/doxygen/DoxyMain.md +++ b/docs/doxygen/DoxyMain.md @@ -3,5 +3,3 @@ DPsim is a solver library for dynamic power system simulation. The [main documentation](https://dpsim.fein-aachen.org/) has build / installation instructions, links to examples and explains the concepts implemented in DPsim as well as its architecture. - - diff --git a/docs/hugo/.gitignore b/docs/hugo/.gitignore index d55f5c85a2..46949d0d5c 100644 --- a/docs/hugo/.gitignore +++ b/docs/hugo/.gitignore @@ -2,4 +2,3 @@ public resources node_modules .hugo_build.lock - diff --git a/docs/hugo/Dockerfile b/docs/hugo/Dockerfile index ca0a7be64a..a4a88b8d29 100644 --- a/docs/hugo/Dockerfile +++ b/docs/hugo/Dockerfile @@ -3,21 +3,21 @@ FROM fedora:34 RUN dnf -y update RUN dnf -y install \ - pandoc \ - wget \ - git \ - nodejs + pandoc \ + wget \ + git \ + nodejs WORKDIR /hugo RUN wget https://github.com/gohugoio/hugo/releases/download/v0.95.0/hugo_extended_0.95.0_Linux-64bit.tar.gz && \ - tar -xvf hugo_extended_0.95.0_Linux-64bit.tar.gz && \ - install hugo /usr/bin + tar -xvf hugo_extended_0.95.0_Linux-64bit.tar.gz && \ + install hugo /usr/bin WORKDIR /website -# this is installed by the entrypoint script in the mounted volume +# This is installed by the entrypoint script in the mounted volume # npm install -D --save autoprefixer # npm install -D --save postcss-cli ENTRYPOINT ["./docker-entrypoint.sh"] -EXPOSE 1313 \ No newline at end of file +EXPOSE 1313 diff --git a/docs/hugo/config.toml b/docs/hugo/config.toml index 3489d1fe08..284baa0b1d 100644 --- a/docs/hugo/config.toml +++ b/docs/hugo/config.toml @@ -23,13 +23,13 @@ category = "categories" [params.taxonomy] # set taxonomyCloud = [] to hide taxonomy clouds -taxonomyCloud = ["tags", "categories"] +taxonomyCloud = ["tags", "categories"] # If used, must have same length as taxonomyCloud -taxonomyCloudTitle = ["Tag Cloud", "Categories"] +taxonomyCloudTitle = ["Tag Cloud", "Categories"] # set taxonomyPageHeader = [] to hide taxonomies on the page headers -taxonomyPageHeader = ["tags", "categories"] +taxonomyPageHeader = ["tags", "categories"] # Highlighting config @@ -95,13 +95,13 @@ copyright = "The DPsim Authors" # This menu appears only if you have at least one [params.versions] set. version_menu = "Releases" -# Flag used in the "version-banner" partial to decide whether to display a +# Flag used in the "version-banner" partial to decide whether to display a # banner on every page indicating that this is an archived version of the docs. # Set this flag to "true" if you want to display the banner. archived_version = false # The version number for the version of the docs represented in this doc set. -# Used in the "version-banner" partial to display a version number for the +# Used in the "version-banner" partial to display a version number for the # current doc set. version = "0.0" @@ -159,7 +159,7 @@ yes = 'Glad to hear it! Please tell us how we can improve.' # Adds a reading time to the top of each doc. -# If you want this feature, but occasionally need to remove the Reading time from a single page, +# If you want this feature, but occasionally need to remove the Reading time from a single page, # add "hide_readingtime: true" to the page's front matter [params.ui.readingtime] enable = false @@ -222,4 +222,4 @@ enable = true disable = false [[module.imports]] path = "github.com/google/docsy/dependencies" - disable = false \ No newline at end of file + disable = false diff --git a/docs/hugo/content/en/_index.html b/docs/hugo/content/en/_index.html index aa7017f24a..7449de0362 100644 --- a/docs/hugo/content/en/_index.html +++ b/docs/hugo/content/en/_index.html @@ -19,4 +19,3 @@ Photo by NASA on Unsplash {{< /blocks/section >}} - diff --git a/docs/hugo/content/en/docs/Concepts/dyn-phasors.md b/docs/hugo/content/en/docs/Concepts/dyn-phasors.md index 9f6874800d..05604f7f8b 100644 --- a/docs/hugo/content/en/docs/Concepts/dyn-phasors.md +++ b/docs/hugo/content/en/docs/Concepts/dyn-phasors.md @@ -10,7 +10,7 @@ A few years later, dynamic phasors were also employed for power system simulatio In [Strunz2006](https://ieeexplore.ieee.org/document/4026700) the authors combine the dynamic phasor approach with the Electromagnetic Transients Program (EMTP) simulator concept which includes Modified Nodal Analysis (MNA). Further research topics include fault and stability analysis under unbalanced conditions as presented in [Stankovic2000](https://ieeexplore.ieee.org/document/871734) and also rotating machine models have been developed in dynamic phasors [Zhang 2007](https://ieeexplore.ieee.org/document/4282063). -## Bandpass Signals and Baseband Representation +# Bandpass Signals and Baseband Representation Although here, dynamic phasors are presented as a power system modelling tool, it should be noted that the concept is also known in other domains, for example, microwave and communications engineering [Maas2003](https://ieeexplore.ieee.org/document/9100822), [Suarez2009](https://ieeexplore.ieee.org/book/5236646), [Haykin2009](https://isbnsearch.org/isbn/9780471697909), [Proakis2001](https://isbnsearch.org/isbn/0131589326). In these domains, the approach is often denoted as base band representation or complex envelope. @@ -18,4 +18,3 @@ Another common term coming from power electrical engineering is shifted frequenc In the following, the general approach of dynamic phasors for power system simulation is explained starting from the idea of bandpass signals. This is because the 50 Hz or 60 Hz fundamental and small deviations from it can be seen as such a bandpass signal. Futhermore, higher frequencies, for example, generated by power electronics can be modelled in a similar way. - diff --git a/docs/hugo/content/en/docs/Concepts/nodal-analysis.md b/docs/hugo/content/en/docs/Concepts/nodal-analysis.md index 155befda57..b9b0c362a4 100644 --- a/docs/hugo/content/en/docs/Concepts/nodal-analysis.md +++ b/docs/hugo/content/en/docs/Concepts/nodal-analysis.md @@ -28,4 +28,7 @@ A circuit can be solved using Nodal Analysis as follows * Write $n-1$ KCL based equations in terms of node voltage variable. The resulting equations can be written in matrix form and have to be solved for $v$. -$$\boldsymbol{Y} \boldsymbol{v} = \boldsymbol{i}$$ + +```math +\boldsymbol{Y} \boldsymbol{v} = \boldsymbol{i} +``` diff --git a/docs/hugo/content/en/docs/Concepts/powerflow.md b/docs/hugo/content/en/docs/Concepts/powerflow.md index 6caefc9c50..4d667ed606 100644 --- a/docs/hugo/content/en/docs/Concepts/powerflow.md +++ b/docs/hugo/content/en/docs/Concepts/powerflow.md @@ -8,7 +8,8 @@ The power flow problem is about the calculation of voltage magnitudes and angles The solution is obtained from a given set of voltage magnitudes and power levels for a specific model of the network configuration. The power flow solution exhibits the voltages and angles at all buses and real and reactive flows can be deduced from the same. -## Power System Model +# Power System Model + Power systems are modeled as a network of buses (nodes) and branches (lines). To a network bus, components such a generator, load, and transmission substation can be connected. Each bus in the network is fully described by the following four electrical quantities: @@ -21,39 +22,53 @@ Each bus in the network is fully described by the following four electrical quan There are three types of networks buses: VD bus, PV bus and PQ bus. Depending on the type of the bus, two of the four electrical quantities are specified as shown in the table below. -| Bus Type | Known | Unknown | -| --- | --- | --- | -| $VD$ | $\vert V_{k} \vert, \theta_{k}$ | $P_{k}, Q_{k}$ | -| $PV$ | $P_{k}, \vert V_{k} \vert$ | $Q_{k}, \theta_{k}$ | -| $PQ$ | $P_{k}, Q_{k}$ | $\vert V_{k} \vert, \theta_{k}$ | +| Bus Type | Known | Unknown | +| --- | --- | --- | +| $VD$ | $\vert V_{k} \vert, \theta_{k}$ | $P_{k}, Q_{k}$ | +| $PV$ | $P_{k}, \vert V_{k} \vert$ | $Q_{k}, \theta_{k}$ | +| $PQ$ | $P_{k}, Q_{k}$ | $\vert V_{k} \vert, \theta_{k}$ | + +# Single Phase Power Flow Problem -## Single Phase Power Flow Problem The power flow problem can be expressed by the goal to bring a mismatch function $\vec{f}$ to zero. The value of the mismatch function depends on a solution vector $\vec{x}$: -$$ \vec{f}(\vec{x}) = 0 $$ + +```math +\vec{f}(\vec{x}) = 0 +``` As $\vec{f}(\vec{x})$ will be nonlinear, the equation system will be solved with Newton-Raphson: -$$-\textbf{J}(\vec{x}) \Delta \vec{x} = \vec{f} (\vec{x})$$ +```math +-\textbf{J}(\vec{x}) \Delta \vec{x} = \vec{f} (\vec{x}) +``` where $\Delta \vec{x}$ is the correction of the solution vector and $\textbf{J}(\vec{x})$ is the Jacobian matrix. The solution vector $\vec{x}$ represents the voltage $\vec{V}$ by polar or cartesian quantities. The mismatch function $\vec{f}$ will either represent the power mismatch $\Delta \vec{S}$ in terms of -$$\left [ \begin{array}{c} \Delta \vec{P} \\ \Delta \vec{Q} \end{array} \right ]$$ +```math +\left [ \begin{array}{c} \Delta \vec{P} \\ \Delta \vec{Q} \end{array} \right ] +``` or the current mismatch $\Delta \vec{I}$ in terms of -$$\left [ \begin{array}{c} \Delta \vec{I_{real}} \\ \Delta \vec{I_{imag}} \end{array} \right ]$$ +```math +\left [ \begin{array}{c} \Delta \vec{I_{real}} \\ \Delta \vec{I_{imag}} \end{array} \right ] +``` where the vectors split the complex quantities into real and imaginary parts. Futhermore, the solution vector $\vec{x}$ will represent $\vec{V}$ either by polar coordinates -$$\left [ \begin{array}{c} \vec{\delta} \\ \vert \vec{V} \vert \end{array} \right ]$$ +```math +\left [ \begin{array}{c} \vec{\delta} \\ \vert \vec{V} \vert \end{array} \right ] +``` or rectangular coordinates -$$\left [ \begin{array}{c} \vec{V_{real}} \\ \vec{V_{imag}} \end{array} \right ]$$ +```math +\left [ \begin{array}{c} \vec{V_{real}} \\ \vec{V_{imag}} \end{array} \right ] +``` This results in four different formulations of the powerflow problem: @@ -64,23 +79,28 @@ This results in four different formulations of the powerflow problem: To solve the problem using NR, we need to formulate $\textbf{J} (\vec{x})$ and $\vec{f} (\vec{x})$ for each powerflow problem formulation. -### Powerflow Problem with Power Mismatch Function and Polar Coordinates +## Powerflow Problem with Power Mismatch Function and Polar Coordinates -#### Formulation of Mismatch Function +### Formulation of Mismatch Function The injected power at a node $k$ is given by: -$$S_{k} = V_{k} I _{k}^{*}$$ + +```math +S_{k} = V_{k} I _{k}^{*} +``` The current injection into any bus $k$ may be expressed as: -$$ + +```math I_{k} = \sum_{j=1}^{N} Y_{kj} V_{j} -$$ +``` Substitution yields: + ```math \begin{align} S_{k} &= V_{k} \left ( \sum_{j=1}^{N} Y_{kj} V_{j} \right )^{*} \nonumber \\ - &= V_{k} \sum_{j=1}^{N} Y_{kj}^{*} V_{j} ^{*} \nonumber + &= V_{k} \sum_{j=1}^{N} Y_{kj}^{*} V_{j} ^{*} \nonumber \end{align} ``` @@ -90,11 +110,11 @@ Then we may rewrite the last equation: ```math \begin{align} S_{k} &= V_{k} \sum_{j=1}^{N} Y_{kj}^{*} V_{j}^{*} \nonumber \\ - &= \vert V_{k} \vert \angle \theta_{k} \sum_{j=1}^{N} (G_{kj} + jB_{kj})^{*} ( \vert V_{j} \vert \angle \theta_{j})^{*} \nonumber \\ - &= \vert V_{k} \vert \angle \theta_{k} \sum_{j=1}^{N} (G_{kj} - jB_{kj}) ( \vert V_{j} \vert \angle - \theta_{j}) \nonumber \\ - &= \sum_{j=1} ^{N} \vert V_{k} \vert \angle \theta_{k} ( \vert V_{j} \vert \angle - \theta_{j}) (G_{kj} - jB_{kj}) \nonumber \\ - &= \sum_{j=1} ^{N} \left ( \vert V_{k} \vert \vert V_{j} \vert \angle (\theta_{k} - \theta_{j}) \right ) (G_{kj} - jB_{kj}) \nonumber \\ - &= \sum_{j=1} ^{N} \vert V_{k} \vert \vert V_{j} \vert \left ( cos(\theta_{k} - \theta_{j}) + jsin(\theta_{k} - \theta_{j}) \right ) (G_{kj} - jB_{kj}) + &= \vert V_{k} \vert \angle \theta_{k} \sum_{j=1}^{N} (G_{kj} + jB_{kj})^{*} ( \vert V_{j} \vert \angle \theta_{j})^{*} \nonumber \\ + &= \vert V_{k} \vert \angle \theta_{k} \sum_{j=1}^{N} (G_{kj} - jB_{kj}) ( \vert V_{j} \vert \angle - \theta_{j}) \nonumber \\ + &= \sum_{j=1} ^{N} \vert V_{k} \vert \angle \theta_{k} ( \vert V_{j} \vert \angle - \theta_{j}) (G_{kj} - jB_{kj}) \nonumber \\ + &= \sum_{j=1} ^{N} \left ( \vert V_{k} \vert \vert V_{j} \vert \angle (\theta_{k} - \theta_{j}) \right ) (G_{kj} - jB_{kj}) \nonumber \\ + &= \sum_{j=1} ^{N} \vert V_{k} \vert \vert V_{j} \vert \left ( cos(\theta_{k} - \theta_{j}) + jsin(\theta_{k} - \theta_{j}) \right ) (G_{kj} - jB_{kj}) \end{align} ``` @@ -103,7 +123,7 @@ If we now perform the algebraic multiplication of the two terms inside the paren ```math \begin{align} {P}_{k} = \sum_{j=1}^{N} \vert V_{k} \vert \vert V_{j} \vert \left ( G_{kj}cos(\theta_{k} - \theta_{j}) + B_{kj} sin(\theta_{k} - \theta_{j}) \right ) \\ -{Q}_{k} = \sum_{j=1}^{N} \vert V_{k} \vert \vert V_{j} \vert \left ( G_{kj}sin(\theta_{k} - \theta_{j}) - B_{kj} cos(\theta_{k} - \theta_{j}) \right ) +{Q}_{k} = \sum_{j=1}^{N} \vert V_{k} \vert \vert V_{j} \vert \left ( G_{kj}sin(\theta_{k} - \theta_{j}) - B_{kj} cos(\theta_{k} - \theta_{j}) \right ) \end{align} ``` @@ -116,12 +136,13 @@ We define the vector of unknown as the composite vector of unknown angles $\vec{ ```math \begin{align} \vec{x} = \left[ \begin{array}{c} \vec{\theta} \\ \vert \vec{V} \vert \\ \end{array} \right ] - = \left[ \begin{array}{c} \theta_{2} \\ \theta_{3} \\ \vdots \\ \theta_{N} \\ \vert V_{N_{PV+1}} \vert \\ \vert V_{N_{PV+2}} \vert \\ \vdots \\ \vert V_{N} \vert \end{array} \right] + = \left[ \begin{array}{c} \theta_{2} \\ \theta_{3} \\ \vdots \\ \theta_{N} \\ \vert V_{N_{PV+1}} \vert \\ \vert V_{N_{PV+2}} \vert \\ \vdots \\ \vert V_{N} \vert \end{array} \right] \end{align} ``` The right-hand sides of equations (2) and (3) depend on the elements of the unknown vector $\vec{x}$. Expressing this dependency more explicitly, we rewrite these equations as: + ```math \begin{align} P_{k} = P_{k} (\vec{x}) \Rightarrow P_{k}(\vec{x}) - P_{k} &= 0 \quad \quad k = 2,...,N \\ @@ -130,20 +151,23 @@ Q_{k} = Q_{k} (\vec{x}) \Rightarrow Q_{k} (\vec{x}) - Q_{k} &= 0 \quad \quad k = ``` We now define the mismatch vector $\vec{f} (\vec{x})$ as: + ```math \begin{align} \vec{f} (\vec{x}) = \left [ \begin{array}{c} f_{1}(\vec{x}) \\ \vdots \\ f_{N-1}(\vec{x}) \\ ------ \\ f_{N}(\vec{x}) \\ \vdots \\ f_{2N-N_{PV} -1}(\vec{x}) \end{array} \right ] - = \left [ \begin{array}{c} P_{2}(\vec{x}) - P_{2} \\ \vdots \\ P_{N}(\vec{x}) - P_{N} \\ --------- \\ Q_{N_{PV}+1}(\vec{x}) - Q_{N_{PV}+1} \\ \vdots \\ Q_{N}(\vec{x}) - Q_{N} \end{array} \right] - = \left [ \begin{array}{c} \Delta P_{2} \\ \vdots \\ \Delta P_{N} \\ ------ \\ \Delta Q_{N_{PV}+1} \\ \vdots \\ \Delta Q_{N} \end{array} \right ] - = \vec{0} + = \left [ \begin{array}{c} P_{2}(\vec{x}) - P_{2} \\ \vdots \\ P_{N}(\vec{x}) - P_{N} \\ --------- \\ Q_{N_{PV}+1}(\vec{x}) - Q_{N_{PV}+1} \\ \vdots \\ Q_{N}(\vec{x}) - Q_{N} \end{array} \right] + = \left [ \begin{array}{c} \Delta P_{2} \\ \vdots \\ \Delta P_{N} \\ ------ \\ \Delta Q_{N_{PV}+1} \\ \vdots \\ \Delta Q_{N} \end{array} \right ] + = \vec{0} \end{align} ``` + That is a system of nonlinear equations. This nonlinearity comes from the fact that $P_{k}$ and $Q_{k}$ have terms containing products of some of the unknowns and also terms containing trigonometric functions of some the unknowns. -#### Formulation of Jacobian +### Formulation of Jacobian As discussed in the previous section, the power flow problem will be solved using the Newton-Raphson method. Here, the Jacobian matrix is obtained by taking all first-order partial derivates of the power mismatch functions with respect to the voltage angles $\theta_{k}$ and magnitudes $\vert V_{k} \vert$ as: + ```math \begin{align} J_{jk}^{P \theta} &= \frac{\partial P_{j} (\vec{x} ) } {\partial \theta_{k}} = \vert V_{j} \vert \vert V_{k} \vert \left ( G_{jk} sin(\theta_{j} - \theta_{k}) - B_{jk} cos(\theta_{j} - \theta_{k} ) \right ) \\ @@ -158,19 +182,20 @@ J_{jj}^{QV} &= \frac{\partial Q_{j}(\vec{x})}{\partial \vert V_{j} \vert } = \fr ``` The linear system of equations that is solved in every Newton iteration can be written in matrix form as follows: + ```math \begin{align} --\left [ \begin{array}{cccccc} - \frac{\partial \Delta P_{2} }{\partial \theta_{2}} & \cdots & \frac{\partial \Delta P_{2} }{\partial \theta_{N}} & - \frac{\partial \Delta P_{2} }{\partial \vert V_{N_{G+1}} \vert} & \cdots & \frac{\partial \Delta P_{2} }{\partial \vert V_{N} \vert} \\ - \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ - \frac{\partial \Delta P_{N} }{\partial \theta_{2}} & \cdots & \frac{\partial \Delta P_{N}}{\partial \theta_{N}} & - \frac{\partial \Delta P_{N}}{\partial \vert V_{N_{G+1}} \vert } & \cdots & \frac{\partial \Delta P_{N}}{\partial \vert V_{N} \vert} \\ - \frac{\partial \Delta Q_{N_{G+1}} }{\partial \theta_{2}} & \cdots & \frac{\partial \Delta Q_{N_{G+1}} }{\partial \theta_{N}} & - \frac{\partial \Delta Q_{N_{G+1}} }{\partial \vert V_{N_{G+1}} \vert } & \cdots & \frac{\partial \Delta Q_{N_{G+1}} }{\partial \vert V_{N} \vert} \\ - \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ - \frac{\partial \Delta Q_{N}}{\partial \theta_{2}} & \cdots & \frac{\partial \Delta Q_{N}}{\partial \theta_{N}} & - \frac{\partial \Delta Q_{N}}{\partial \vert V_{N_{G+1}} \vert } & \cdots & \frac{\partial \Delta Q_{N}}{\partial \vert V_{N} \vert} +-\left [ \begin{array}{cccccc} + \frac{\partial \Delta P_{2} }{\partial \theta_{2}} & \cdots & \frac{\partial \Delta P_{2} }{\partial \theta_{N}} & + \frac{\partial \Delta P_{2} }{\partial \vert V_{N_{G+1}} \vert} & \cdots & \frac{\partial \Delta P_{2} }{\partial \vert V_{N} \vert} \\ + \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ + \frac{\partial \Delta P_{N} }{\partial \theta_{2}} & \cdots & \frac{\partial \Delta P_{N}}{\partial \theta_{N}} & + \frac{\partial \Delta P_{N}}{\partial \vert V_{N_{G+1}} \vert } & \cdots & \frac{\partial \Delta P_{N}}{\partial \vert V_{N} \vert} \\ + \frac{\partial \Delta Q_{N_{G+1}} }{\partial \theta_{2}} & \cdots & \frac{\partial \Delta Q_{N_{G+1}} }{\partial \theta_{N}} & + \frac{\partial \Delta Q_{N_{G+1}} }{\partial \vert V_{N_{G+1}} \vert } & \cdots & \frac{\partial \Delta Q_{N_{G+1}} }{\partial \vert V_{N} \vert} \\ + \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ + \frac{\partial \Delta Q_{N}}{\partial \theta_{2}} & \cdots & \frac{\partial \Delta Q_{N}}{\partial \theta_{N}} & + \frac{\partial \Delta Q_{N}}{\partial \vert V_{N_{G+1}} \vert } & \cdots & \frac{\partial \Delta Q_{N}}{\partial \vert V_{N} \vert} \end{array} \right ] \left [ \begin{array}{c} \Delta \theta_{2} \\ \vdots \\ \Delta \theta_{N} \\ \Delta \vert V_{N_{G+1}} \vert \\ \vdots \\ \Delta \vert V_{N} \vert \end{array} \right ] = \left [ \begin{array}{c} \Delta P_{2} \\ \vdots \\ \Delta P_{N} \\ \Delta Q_{N_{G+1}} \\ \vdots \\ \Delta Q_{N} \end{array} \right ] @@ -180,21 +205,22 @@ The linear system of equations that is solved in every Newton iteration can be w ## Solution of the Problem The solution update formula is given by: + ```math \begin{align} - \vec{x}^{(i+1)} = \vec{x}^{(i)} + \Delta \vec{x}^{(i)} = \vec{x}^{(i)} - \textbf{J}^{-1} \vec{f} (\vec{x}^{(i)}) + \vec{x}^{(i+1)} = \vec{x}^{(i)} + \Delta \vec{x}^{(i)} = \vec{x}^{(i)} - \textbf{J}^{-1} \vec{f} (\vec{x}^{(i)}) \end{align} ``` To sum up, the NR algorithm, for application to the power flow problem is: 1. Set the iteration counter to $i=1$. Use the initial solution $V_{i} = 1 \angle 0^{\circ}$ -2. Compute the mismatch vector $\vec{f}({\vec{x}})$ using the power flow equations -3. Perform the following stopping criterion tests: - * If $\vert \Delta P_{i} \vert < \epsilon_{P}$ for all type PQ and PV buses and - * If $\vert \Delta Q_{i} \vert < \epsilon_{Q}$ for all type PQ - * Then go to step 6 - * Otherwise, go to step 4. -4. Evaluate the Jacobian matrix $\textbf{J}^{(i)}$ and compute $\Delta \vec{x}^{(i)}$. -5. Compute the update solution vector $\vec{x}^{(i+1)}$. Return to step 3. -6. Stop. \ No newline at end of file +1. Compute the mismatch vector $\vec{f}({\vec{x}})$ using the power flow equations +1. Perform the following stopping criterion tests: + * If $\vert \Delta P_{i} \vert < \epsilon_{P}$ for all type PQ and PV buses and + * If $\vert \Delta Q_{i} \vert < \epsilon_{Q}$ for all type PQ + * Then go to step 6 + * Otherwise, go to step 4. +1. Evaluate the Jacobian matrix $\textbf{J}^{(i)}$ and compute $\Delta \vec{x}^{(i)}$. +1. Compute the update solution vector $\vec{x}^{(i+1)}$. Return to step 3. +1. Stop. diff --git a/docs/hugo/content/en/docs/Contribution guidelines/index.md b/docs/hugo/content/en/docs/Contribution guidelines/index.md index e0960c292a..151aca3c9a 100644 --- a/docs/hugo/content/en/docs/Contribution guidelines/index.md +++ b/docs/hugo/content/en/docs/Contribution guidelines/index.md @@ -7,5 +7,5 @@ description: > How to contribute to DPsim. --- -We'd love to accept your patches and contributions to this project. +We'd love to accept your patches and contributions to this project. Please send us a [pull request](https://github.com/sogno-platform/dpsim/pulls) or get in touch with us via mail or [slack](https://lfenergy.slack.com/archives/C054GB551TL) if you would like to contribute. diff --git a/docs/hugo/content/en/docs/Development/Debugging.md b/docs/hugo/content/en/docs/Development/Debugging.md deleted file mode 100644 index f313f9fcd6..0000000000 --- a/docs/hugo/content/en/docs/Development/Debugging.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: "Debugging" -linkTitle: "Debugging" ---- - -## Mixed Python C++ Debugging - -### Prerequisites - -Your vscode launch.json should have two configurations, one to launch the python process and one to attach gdb: - - { - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Current File", - "type": "python", - "request": "launch", - "program": "${file}", - "console": "integratedTerminal", - "stopOnEntry": true, - "env": {"PYTHONPATH": "${workspaceFolder}/build${pathSeparator}${env:PYTHONPATH}"} - }, - { - "name": "(gdb) Attach", - "type": "cppdbg", - "request": "attach", - "program": "/usr/bin/python", - "processId": "${command:pickProcess}", - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - } - ] - } - -The python debugger will stop on entry ("stopOnEntry": true). -Make sure to adapt your PYTHONPATH variable if necessary. - -The C++ code has to be build in debug mode - - cmake .. -DCMAKE_BUILD_TYPE=Debug - -### Attaching C++ Debugger - -- open the python example to be debugged -- go to the debug menu and select / run the "Python: Current File" configuration -- the python debugger should stop at entry -- set C++ breakpoints -- go to the debug menu and run the "(gdb) Attach" configuration -- select a process… choose the python process with the “—adapter-access-token” part -- you can view the whole description when you hover over the process with the mouse -- press play to continue Python debugging… the c++ debugger will stop at the next breakpoint - -You can automate this by using the vscode extension “Python C++ Debugger” and by adding this configuration to the launch.json above: - - { - "name": "Python C++ Debugger", - "type": "pythoncpp", - "request": "launch", - "pythonConfig": "custom", - "pythonLaunchName": "Python: Current File", - "cppConfig": "default (gdb) Attach" - } - -This will automatically run both debuggers and select the current process. - -It can take a while before the debugger hits the C++ breakpoints. - - -## C++ Debugging - -Use the following launch.json for vscode and set the program path: - - { - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/dpsim/build/Examples/Cxx/example", - "args": [], - "stopAtEntry": true, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] - } - ] - } \ No newline at end of file diff --git a/docs/hugo/content/en/docs/Development/Guidelines.md b/docs/hugo/content/en/docs/Development/Guidelines.md deleted file mode 100644 index ecdcf238d5..0000000000 --- a/docs/hugo/content/en/docs/Development/Guidelines.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: "Guidelines" -linkTitle: "Guidelines" ---- - -This is a summary of general guidelines for the development of DPsim. - -## Scaling of Voltages and Currents - -Voltage quantities are expressed either as phase-to-phase RMS values (denominated as `RMS3PH`) or as phase-to-ground peak values (denominated as `PEAK1PH`): - -- Initialisation quantities (e.g. `initialSingleVoltage` of `SimPowerComp`) as `RMS3PH` values -- Simulation quantities in both `SP` and `DP` domain (e.g. `mIntfVoltage` of `DP::Ph1::PiLine`) as `RMS3PH values` -- Simulation quantities in the `EMT` domain (e.g. `mIntfVoltage` of `EMT::Ph3::Transformer`) as `PEAK1PH` values - -Current quantities are expressed either as `RMS` or as `PEAK` values: - -- Simulation quantities in both `SP` and `DP` domain (e.g. `mIntfCurrent` of `DP::Ph1::PiLine`) as `RMS` values -- Simulation quantities in the `EMT` domain (e.g. `mIntfCurrent` of `EMT::Ph3::Transformer`) as `PEAK` values - - -## Logging - -Debug or trace should be the default log level for information that might be nice to have but not necessary for every simulation case. - -Calls to the logger that might occur during simulation must use spdlog macros, like SPDLOG_LOGGER_INFO. - -## Creating New Releases - -Although DPsim currently does not have any conventions on versioning, the periodic creation of -new versions can help to mark significant changes and to analyze new portions of code using tools like SonarCloud. - -A new version of DPsim has to be indicated as follows: -- Create a new tag with an increased version number -- Update setup.cfg -- Update CMakeLists.txt -- Update sonar-project.properties - -Due to the creation of a new tag, a new PyPi package will be deployed automatically. -To release an updated Docker image, the container workflow needs to be triggered manually. diff --git a/docs/hugo/content/en/docs/Development/_index.md b/docs/hugo/content/en/docs/Development/_index.md index 2070ce0bee..0053dcf5be 100644 --- a/docs/hugo/content/en/docs/Development/_index.md +++ b/docs/hugo/content/en/docs/Development/_index.md @@ -6,18 +6,18 @@ description: > How to extend DPsim. --- -## Environment +# Environment We recommend the following development tools: - Editor: [Visual Studio Code](https://code.visualstudio.com) - - Extensions: - - [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) - - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) - - [CMake Tools](https://marketplace.visualstudio.com/items?itemName=vector-of-bool.cmake-tools) - - [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) - - [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - - [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) + - Extensions: + - [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) + - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) + - [CMake Tools](https://marketplace.visualstudio.com/items?itemName=vector-of-bool.cmake-tools) + - [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) + - [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) + - [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) - [Docker](https://www.docker.com) - [CMake](https://cmake.org) - [Git](https://git-scm.com) diff --git a/docs/hugo/content/en/docs/Development/debugging.md b/docs/hugo/content/en/docs/Development/debugging.md new file mode 100644 index 0000000000..d4006801c8 --- /dev/null +++ b/docs/hugo/content/en/docs/Development/debugging.md @@ -0,0 +1,110 @@ +--- +title: "Debugging" +linkTitle: "Debugging" +--- + +# Mixed Python C++ Debugging + +## Prerequisites + +Your vscode launch.json should have two configurations, one to launch the python process and one to attach gdb: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "stopOnEntry": true, + "env": {"PYTHONPATH": "${workspaceFolder}/build${pathSeparator}${env:PYTHONPATH}"} + }, + { + "name": "(gdb) Attach", + "type": "cppdbg", + "request": "attach", + "program": "/usr/bin/python", + "processId": "${command:pickProcess}", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} +``` + +The python debugger will stop on entry ("stopOnEntry": true). +Make sure to adapt your PYTHONPATH variable if necessary. + +The C++ code has to be build in debug mode + +```shell +cmake .. -DCMAKE_BUILD_TYPE=Debug +``` + +## Attaching C++ Debugger + +- open the python example to be debugged +- go to the debug menu and select / run the "Python: Current File" configuration +- the python debugger should stop at entry +- set C++ breakpoints +- go to the debug menu and run the "(gdb) Attach" configuration +- select a process… choose the python process with the “—adapter-access-token” part +- you can view the whole description when you hover over the process with the mouse +- press play to continue Python debugging… the c++ debugger will stop at the next breakpoint + +You can automate this by using the vscode extension “Python C++ Debugger” and by adding this configuration to the launch.json above: + +```json +{ + "name": "Python C++ Debugger", + "type": "pythoncpp", + "request": "launch", + "pythonConfig": "custom", + "pythonLaunchName": "Python: Current File", + "cppConfig": "default (gdb) Attach" +} +``` + +This will automatically run both debuggers and select the current process. + +It can take a while before the debugger hits the C++ breakpoints. + +# C++ Debugging + +Use the following launch.json for vscode and set the program path: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dpsim/build/Examples/Cxx/example", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} +``` diff --git a/docs/hugo/content/en/docs/Development/guidelines.md b/docs/hugo/content/en/docs/Development/guidelines.md new file mode 100644 index 0000000000..5cd74875a6 --- /dev/null +++ b/docs/hugo/content/en/docs/Development/guidelines.md @@ -0,0 +1,77 @@ +--- +title: "Guidelines" +linkTitle: "Guidelines" +--- + +This is a summary of general guidelines for the development of DPsim. + +# Scaling of Voltages and Currents + +Voltage quantities are expressed either as phase-to-phase RMS values (denominated as `RMS3PH`) or as phase-to-ground peak values (denominated as `PEAK1PH`): + +- Initialisation quantities (e.g. `initialSingleVoltage` of `SimPowerComp`) as `RMS3PH` values +- Simulation quantities in both `SP` and `DP` domain (e.g. `mIntfVoltage` of `DP::Ph1::PiLine`) as `RMS3PH values` +- Simulation quantities in the `EMT` domain (e.g. `mIntfVoltage` of `EMT::Ph3::Transformer`) as `PEAK1PH` values + +Current quantities are expressed either as `RMS` or as `PEAK` values: + +- Simulation quantities in both `SP` and `DP` domain (e.g. `mIntfCurrent` of `DP::Ph1::PiLine`) as `RMS` values +- Simulation quantities in the `EMT` domain (e.g. `mIntfCurrent` of `EMT::Ph3::Transformer`) as `PEAK` values + +# Logging + +Debug or trace should be the default log level for information that might be nice to have but not necessary for every simulation case. + +Calls to the logger that might occur during simulation must use spdlog macros, like `SPDLOG_LOGGER_INFO`. + +# Pull Requests + +There are no strict formal requirements besides the following: + +1. **Developer Certificate of Origin (DCO)** + + We require a Developer Certificate of Origin. See more [here](https://github.com/lf-energy/tac/blob/main/process/contribution_guidelines.md#contribution-sign-off). + +1. **Code Formatting with `pre-commit`** + + We enforce code formatting automatically using `pre-commit`. Please run `pre-commit install` the first time you clone the repository to run `pre-commit` before each commit automatically. If you forgot to do this, you will need to use the command `pre-commit run --all-files` one time to format your changes. + +1. **Development in Forks Only** + + We accept contributions made in forks only. The main repository is not intended for contributor-specific branches. + +1. **SPDX Headers** + + Use SPDX headers to indicate copyright and licensing information, especially when introducing new files to the codebase. For example: + + ```cpp + /* Author: John Smith + * SPDX-FileCopyrightText: 2025 Example.com + * SPDX-License-Identifier: MPL-2.0 + */ + ``` + +# Creating New Releases (info for maintainers) + +DPsim currently uses to [Semantic Versioning](https://semver.org/). The periodic creation of +new versions can help to mark significant changes and to analyze new portions of code using tools like SonarCloud. + +A new version of DPsim has to be indicated as follows: + +- Update setup.cfg +- Update CMakeLists.txt +- Update sonar-project.properties +- Update CHANGELOG.md and include all the unreleaed changes in the list +- Create a new tag with an increased version number (can be done during the Release in GitHub) + +## Python Packages + +Due to the creation of a new tag, a new PyPi package will be deployed automatically. + +Only Linux packages are currently available, other platforms will be supported in the future. + +## Container Images + +To release an updated Docker image, the container workflow needs to be triggered manually. + +If a Pull Request changes a container image, this is not updated automatically in the container image register. diff --git a/docs/hugo/content/en/docs/Getting started/_index.md b/docs/hugo/content/en/docs/Getting started/_index.md index 6a62fa6b16..8c0ab9de09 100644 --- a/docs/hugo/content/en/docs/Getting started/_index.md +++ b/docs/hugo/content/en/docs/Getting started/_index.md @@ -5,5 +5,3 @@ weight: 2 description: > How to install, build and run the DPsim project. --- - - diff --git a/docs/hugo/content/en/docs/Getting started/build.md b/docs/hugo/content/en/docs/Getting started/build.md index 03872b61b0..afeb91bc2a 100644 --- a/docs/hugo/content/en/docs/Getting started/build.md +++ b/docs/hugo/content/en/docs/Getting started/build.md @@ -4,82 +4,109 @@ linkTitle: "Build" date: 2023-05-03 --- -## Docker based +# Docker based Clone the repository - $ git clone git@github.com:sogno-platform/dpsim.git +```shell +git clone git@github.com:sogno-platform/dpsim.git +``` or using https if you do not have an account - $ git clone https://github.com/sogno-platform/dpsim.git +```shell +git clone https://github.com/sogno-platform/dpsim.git +``` In the repository, there is a Docker file with all required dependencies - $ cd dpsim - $ docker build -t sogno/dpsim:dev -f Packaging/Docker/Dockerfile.dev . +```shell +cd dpsim +docker build -t sogno/dpsim:dev -f packaging/Docker/Dockerfile.dev . +``` Alternatively, the image can be pulled from DockerHub like so - $ docker pull sogno/dpsim:dev +```shell +docker pull sogno/dpsim:dev +``` For OS specific instructions on how to install requirements, see the sections below. Next, run a Docker container - $ cd dpsim - $ docker run -it -p 8888:8888 -v $(pwd):/dpsim --privileged sogno/dpsim:dev bash +```shell +cd dpsim +docker run -it -p 8888:8888 -v $(pwd):/dpsim --privileged sogno/dpsim:dev bash +``` The option `-p` maps the port 8888 of the container to the docker host. This is required to access the jupyter lab instance inside the container. The option `--privileged` is required for debug builds. For Windows, you might need to specify the current directory with curly brackets - $ docker run -it -p 8888:8888 -v ${pwd}:/dpsim --privileged sogno/dpsim:dev bash +```shell +docker run -it -p 8888:8888 -v ${pwd}:/dpsim --privileged sogno/dpsim:dev bash +``` Now, you should be in an interactive session inside the docker container. The DPsim C++ and Python library without C++ examples or documentation can be built as follows - $ cd /dpsim - $ mkdir build && cd build - $ cmake .. - $ cmake --build . --target dpsimpy +```shell +cd /dpsim +mkdir build && cd build +cmake .. +cmake --build . --target dpsimpy +``` If you need other libraries that are not built by default, you need to target them specifically, for example if you need `dpsimpy´ and ´dpsimpyvillas´: - $ cmake --build . --target dpsimpy dpsimpyvillas +```shell +cmake --build . --target dpsimpy dpsimpyvillas +``` To build everything run - $ cmake --build . +```shell +cmake --build . +``` To use other libraries that are installed, use the relevant option defined in the CMakeList.txt files, for example for GSL below, and then build as usual: - - $ cmake .. -DWITH_GSL=ON + +```shell +cmake .. -DWITH_GSL=ON +``` If you would like to use the Python package, it has to be added to the path. The following command adds the dpsimpy C++/Python package as well as the dpsim pure Python package. - $ cd /dpsim/build - $ export PYTHONPATH=$(pwd):$(pwd)/../python/src/ +```shell +cd /dpsim/build +export PYTHONPATH=$(pwd):$(pwd)/../python/src/ +``` If you are using `conda` or other ways to develop with environments, please keep in mind that this will become specific for your setup. For this case, from within the environment already active: - $ cd /dpsim/build - $ conda develop $(pwd) && conda develop $(pwd)/Source/Python && conda develop $(pwd)/../Source/Python - -To run jupyter lab +```shell +cd /dpsim/build +conda develop $(pwd) && conda develop $(pwd)/Source/Python && conda develop $(pwd)/../Source/Python +``` - $ cd /dpsim - $ jupyter lab --ip="0.0.0.0" --allow-root --no-browser +To run JupyterLab -To install dpsim run +```shell +cd /dpsim +jupyter lab --ip="0.0.0.0" --allow-root --no-browser +``` - $ cd /dpsim/build - $ sudo make install +To install DPsim run +```shell +cd /dpsim/build +sudo make install +``` -## CMake for Linux +# CMake for Linux The most recent list of requirements can be found in the Dockerfiles. @@ -91,19 +118,21 @@ If you want to use these optional feature, you have to build them manually. Install Sundials - $ git clone --branch v3.1.1 https://github.com/LLNL/sundials.git - $ mkdir sundials/build - $ pushd sundials/build - $ cmake .. \ - -DBUILD_SHARED_LIBS=ON \ - -DBUILD_STATIC_LIBS=OFF \ - -DEXAMPLES_ENABLE_C=OFF - $ make -j$(nproc) install - $ popd +```shell +git clone --branch v3.1.1 https://github.com/LLNL/sundials.git +mkdir sundials/build +pushd sundials/build +cmake .. \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_STATIC_LIBS=OFF \ + -DEXAMPLES_ENABLE_C=OFF +make -j$(nproc) install +popd +``` The following steps to clone, build and install are the same as for the Docker setup. -## CMake for Windows +# CMake for Windows Make sure that the required dependecies are installed: @@ -117,69 +146,112 @@ Clone the project as explained for Docker. Open a windows command prompt and navigate into the new DPsim folder. Generate a Visual Studio project with CMake and use it to build the project - $ mkdir build - $ cd build - $ cmake -G "Visual Studio 15 2017 Win64" .. +```shell +mkdir build +cd build +cmake -G "Visual Studio 15 2017 Win64" .. +``` Open Visual Studio and load the Visual Studio project from the build directory within the DPsim folder. You can either build the project from within Visual Studio or from the command line by running the following command in the windows command prompt - $ cmake --build . +```shell +cmake --build . +``` To install the Python package use Visual Studio and the Release configuration to build the DPsim Python module and then build the INSTALL project. -## CMake for macOS +# CMake for macOS -Make sure that the required dependecies are installed +Make sure that the required dependencies are installed - $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - $ brew install gcc9 git cmake graphviz python3 gsl eigen spdlog - $ sudo pip3 install numpy +```shell +/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install gcc9 git cmake graphviz python3 gsl eigen spdlog +sudo pip3 install numpy +``` Clone the source as explained for the Docker setup. Compile - $ mkdir build - $ cmake .. - $ make -j$(sysctl -n hw.ncpu) +```shell +mkdir build +cmake .. +make -j$(sysctl -n hw.ncpu) +``` To install the generated Python module to your system - $ sudo make install +```shell +sudo make install +``` - -## Python Package for pypi +# Python Package for pypi Follow the previous steps to set up the Docker container. To build the Python package run - $ python3 setup.py bdist_wheel +```shell +python3 setup.py bdist_wheel +``` + +## Nix + +DPsim can be fully build using [Nix](https://nixos.org/), a declarative package manager for building software reproducible. + +The following steps require a working single-user or multi-user installation of Nix, but not necessarily NixOS. + +DPsim uses Nix's experimental Flake feature which needs to be activated: + +```shell +echo "experimental-features=nix-command flakes" > ~/.config/nix/nix.conf +``` + +Building DPsim, including all its dependencies can be done by running: + +```shell +nix build github:sogno-platform/dpsim +``` + +The build result will be available within the `result` folder of your current directory. + +For development purposes, a local development environment can be setup by you running: + +```shell +nix develop github:sogno-platform/dpsim +``` + +Please note, that the Flake reference above (`github:sogno-platform/dpsim`) can be substituted by a local path (`.`), in case you have locally checked out the DPsim repo. -## Documentation +# Documentation -### Python +## Python Install [Sphinx](https://www.sphinx-doc.org/en/master/) or use the Docker image. Generate the Python documentation by running Sphinx via CMake: - $ mkdir -p build && cd build - $ cmake .. - $ make docs +```shell +mkdir -p build && cd build +cmake .. +make docs +``` The resulting documentation will be generated in `Documentation/html/`. -### C++ +## C++ Install [Doxygen](http://www.doxygen.nl/) or use the Docker image. Generate the C++ documentation by running Doxygen via CMake: - $ mkdir -p build && cd build - $ cmake .. - $ make docs_cxx +```shell +mkdir -p build && cd build +cmake .. +make docs_cxx +``` The resulting documentation will be generated in `Documentation/html/Cxx`. diff --git a/docs/hugo/content/en/docs/Getting started/install.md b/docs/hugo/content/en/docs/Getting started/install.md index 404fa91c3e..3c3c094166 100644 --- a/docs/hugo/content/en/docs/Getting started/install.md +++ b/docs/hugo/content/en/docs/Getting started/install.md @@ -8,45 +8,57 @@ DPsim is a Python module / C++ library for complex power system simulation. As a Python module, the easiest way to get to know DPsim is via [Jupyter Notebooks](https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/). -## Docker +# Docker First, you need to install [Docker](https://docs.docker.com/install/). Then, you could either build a docker image by yourself as described in the build instructions or download a prepared image from Docker Hub as described in the following. To start a Jupyter session, run a DPsim Docker container - $ docker run -p 8888:8888 sogno/dpsim +```shell +docker run -p 8888:8888 sogno/dpsim +``` -And access the session by opening the following link: http://localhost:8888/lab?token=3adaa57df44cea75e60c0169e1b2a98ae8f7de130481b5bc +And access the session by opening the following link: -## Python +# Python in Linux -**Currently, the pypi packages are not maintained. Until we have updated the packages, please use the docker installation.** +DPsim can be installed in Linux as a Python module: -### Prerequisites +```shell +pip install dpsim +``` + +## Prerequisites First, you need to make sure that Python is installed and your version is compatible. An easy way to install Python and all required packages is the [Anaconda distribution](https://www.anaconda.com/). To get started, install the latest installer for Python 3.x from the [downloads section](https://www.anaconda.com/download/). Then, run the Anaconda Prompt and create a new conda environment: - $ conda create -n dpsim python=3.6 +```shell +conda create -n dpsim python=3.13 +``` After creating the environment you need to make sure that it is activated. The current environment is displayed at the beginning of the command line in brackets. It should read *"(dpsim)..."*. In case it is not activated, run: - $ activate dpsim - +```shell +activate dpsim +``` -### Pip Package Installation +## Pip Package Installation -Then, DPsim can be installed as a Python module: +Then, DPsim can be installed as a Python module in Linux: - $ pip install dpsim +```shell +pip install dpsim +``` +Some examples also need additional packages to process the data or show graphics. Please have a look at the import section of them in case you run into any errors. -## From Source +# From Source -To build and install DPsim from the source files, please refer to the build section. \ No newline at end of file +To build and install DPsim from the source files, please refer to the build section. diff --git a/docs/hugo/content/en/docs/Getting started/real-time.md b/docs/hugo/content/en/docs/Getting started/real-time.md index 03175856e0..78bdc262e0 100644 --- a/docs/hugo/content/en/docs/Getting started/real-time.md +++ b/docs/hugo/content/en/docs/Getting started/real-time.md @@ -12,12 +12,12 @@ This is due to operating system noise and other processes interfering with the s With proper tuning, we have achieved real-time time steps as low as 5 us synchronized to a FPGA using VILLASnode. Synchronizing the time step to an external source is only necessary, when very high time step accuracy, with maximum deviations in the nanoseconds, is required. - -## Operating System and Kernel +# Operating System and Kernel Using a Linux kernel with the `PREEMPT_RT` feature improves latency when issuing system calls and enables the FIFO scheduler that lets us avoid preemption during the real-time simulation. Most distributions offer a binary package for a `PREEMPT_RT` enabled kernel. For example on Rocky Linux: + ```bash sudo dnf --enablerepo=rt install kernel-rt kernel-rt-devel ``` @@ -25,32 +25,37 @@ sudo dnf --enablerepo=rt install kernel-rt kernel-rt-devel More aggressive tuning can involve isolating a set of cores for exclusive use by the real-time simulation. This way, the kernel will not schedule any processes on these cores. Add the kernel parameters `isolcpus` and `nohz_full` using, for example, `grubby`: + ```bash sudo grubby --update-kernel=ALL --args="isolcpus=9,11,13,15 nohz_full=9,11,13,15" ``` Something similar, but less invasive and non-permanent can be achieved using `tuna`: + ```bash sudo tuna isolate -c 9,11,13,15 ``` To avoid real-time throttling to cause overruns disable this feature: + ```bash sudo bash -c "echo -1 > /proc/sys/kernel/sched_rt_runtime_us" ``` + Note that this is not persistent when rebooting. -## Simulation Model Tuning +# Simulation Model Tuning Real time capable models cannot issue any system calls during simulation as the context switch to the kernel introduces unacceptable latencies. -This means models cannot allocate memory, use mutexes or other interupt-driven synchronization primitives, read or write data from files. +This means models cannot allocate memory, use mutexes or other interrupt-driven synchronization primitives, read or write data from files. You should turn off logging, when time steps in the low milliseconds are desired. There is a `RealTimeDataLogger` that can be used to output simulation results in these cases. Note however, that this logger pre-allocated the memory required for all of the logging required during simulations. Your machine may run out of memory, when the simulation is long or you log too many signals. You can increase the performance of your simulation by adding the `-flto` and `-march=native` compiler flags: -``` + +```diff diff --git a/CMakeLists.txt b/CMakeLists.txt index 8801cbe8d..4a2843269 100644 --- a/CMakeLists.txt @@ -59,16 +64,17 @@ index 8801cbe8d..4a2843269 100644 check_symbol_exists(timerfd_create sys/timerfd.h HAVE_TIMERFD) check_symbol_exists(getopt_long getopt.h HAVE_GETOPT) if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") -- add_compile_options(-flto -march=native -Ofast) -+ add_compile_options( -Ofast) +- add_compile_options(-Ofast) ++ add_compile_options(-Ofast -flto -march=native) endif() # Get version info and buildid from Git ``` -## Running a Real-Time Simulation +# Running a Real-Time Simulation Before running a simulation, you can run the following commands as root: + ```bash echo "evacuating cores" tuna isolate -c 9,11,13,15 @@ -86,6 +92,7 @@ systemctl stop chronyd As a reference, real-time simulation examples are provided in the `dpsim/examples/cxx` and `dpsim-villas/examples/cxx` folder of the DPsim repository. To benefit from the `PREEMPT_RT` feature and the isolated cores, the simulation has to be started using the `chrt` command to set the scheduling policy and priority, and the `taskset` command to pin the process to the isolated cores. + - [chrt man-page](http://man7.org/linux/man-pages/man1/chrt.1.html) - [taskset man-page](http://man7.org/linux/man-pages/man1/taskset.1.html) diff --git a/docs/hugo/content/en/docs/Models/RLC-Elements/index.md b/docs/hugo/content/en/docs/Models/RLC-Elements/index.md index e9bfbc8ea8..6a0cb72884 100644 --- a/docs/hugo/content/en/docs/Models/RLC-Elements/index.md +++ b/docs/hugo/content/en/docs/Models/RLC-Elements/index.md @@ -4,70 +4,90 @@ linkTitle: "RLC-Elements" date: 2020-03-18 --- -## EMT Equations and Modified Nodal Analysis +# EMT Equations and Modified Nodal Analysis -### Inductance +## Inductance An inductance is described by -$$ - v_j(t) - v_k(t) = v_L(t) = L \frac{\mathrm{d} i_L(t)}{\mathrm{d}t} -$$ + +```math +v_j(t) - v_k(t) = v_L(t) = L \frac{\mathrm{d} i_L(t)}{\mathrm{d}t} +``` + Integration results in an equation to compute the current at time $t$ from a previous state at $t - \Delta t$. -$$ - i_L(t) = i_L(t - \Delta t) + \frac{1}{L} \ \int_{t - \Delta t}^{t} v_L(\tau) \ \mathrm{d} \tau -$$ + +```math +i_L(t) = i_L(t - \Delta t) + \frac{1}{L} \ \int_{t - \Delta t}^{t} v_L(\tau) \ \mathrm{d} \tau +``` + There are various methods to discretize this equation in order to solve it numerically. The trapezoidal rule, an implicit second-order method, is commonly applied for circuit simulation: -$$ - \int_{t - \Delta t}^{t} f(\tau) \ \mathrm{d} \tau \approx \frac{\Delta t}{2}(f(t) + f(t - \Delta t)) -$$ + +```math +\int_{t - \Delta t}^{t} f(\tau) \ \mathrm{d} \tau \approx \frac{\Delta t}{2}(f(t) + f(t - \Delta t)) +``` + Applying the trapezoidal rule to leads to -$$ - i_L(t) = i_L(t - \Delta t) + \frac{\Delta t}{2L}(v_L(t) + v_L(t - \Delta t)) -$$ + +```math +i_L(t) = i_L(t - \Delta t) + \frac{\Delta t}{2L}(v_L(t) + v_L(t - \Delta t)) +``` + This can be rewritten in terms of an equivalent conductance and current source and the number of time steps $k$ with size $\Delta t$. -$$ - i_L(k) = g_L v_L(k) + i_{L,equiv}(k-1) -$$ -$$ - i_{L,equiv}(k-1) = i_L(k-1) + \frac{\Delta t}{2L} v_L(k-1) -$$ -$$ - g_L = \frac{\Delta t}{2L} -$$ + +```math +i_L(k) = g_L v_L(k) + i_{L,equiv}(k-1) +``` + +```math +i_{L,equiv}(k-1) = i_L(k-1) + \frac{\Delta t}{2L} v_L(k-1) +``` + +```math +g_L = \frac{\Delta t}{2L} +``` Hence, components described by differential equations are transformed into a DC equivalent circuit as depicted in the figure below. ![inductance resistive companion](electrical_resistive_companion_inductance.svg) -### Capacitance +## Capacitance The same procedure can be applied to a capacitance. Integration on both side yields -$$ - i_C(t) = C \frac{\mathrm{d}}{\mathrm{d}t} \ v_C(t) -$$ -$$ - v_C(t) = v_C(t - \Delta t) + \frac{1}{C} \int_{t - \Delta t}^t i_C(\tau) \mathrm{d} \tau -$$ + +```math +i_C(t) = C \frac{\mathrm{d}}{\mathrm{d}t} \ v_C(t) +``` + +```math +v_C(t) = v_C(t - \Delta t) + \frac{1}{C} \int_{t - \Delta t}^t i_C(\tau) \mathrm{d} \tau +``` + Finally, the equivalent circuit is described by a current source and a conductance. -$$ - i_{C}(k) = g_{C} v_C(k) + i_{C,equiv}(k-1) -$$ -$$ - i_{C,equiv}(k-1) = -i_{C}(k-1) - g_C v_C(k-1) -$$ -$$ - g_{C} = \frac{2C}{\Delta t} -$$ + +```math +i_{C}(k) = g_{C} v_C(k) + i_{C,equiv}(k-1) +``` + +```math +i_{C,equiv}(k-1) = -i_{C}(k-1) - g_C v_C(k-1) +``` + +```math +g_{C} = \frac{2C}{\Delta t} +``` + This equation set is visualized in the figure below. ![capacitance resistive companion](electrical_resistive_companion_capacitance.svg) Hence, the vector of unknowns $\bm{x}$ and the source vector $\bm{b}$ become time dependent and this leads to the system description: -$$ - \bm{A} \bm{x}(t) = \bm{b}(t) -$$ + +```math +\bm{A} \bm{x}(t) = \bm{b}(t) +``` + To simulate the transient behavior of circuits, this linear equation has to be solved repeatedly. As long as the system topology and the time step is fixed, the system matrix is constant. @@ -77,8 +97,10 @@ The dynamic phasor concept can be integrated with nodal analysis. The overall procedure does not change but the system equations are rewritten using complex numbers and all variables need to be expressed in terms of dynamic phasors. Therefore, the resistive companion representations of inductances and capacitances have to be adapted as well. -### Inductance +## Inductance + In dynamic phasors the integration of the inductance equation yields + ```math \begin{align} \langle v_L \rangle(t) &= \Big \langle L \frac{\mathrm{d} i_L}{\mathrm{d}t} \Big \rangle(t) \nonumber \\ @@ -86,88 +108,107 @@ In dynamic phasors the integration of the inductance equation yields \end{align} ``` -$$ - \langle i_L \rangle(t) = \langle i_L \rangle(t - \Delta t) + \int_{t - \Delta t}^t \frac{1}{L} \langle v_L \rangle(\tau) - j \omega \ \langle i_L \rangle(\tau) \mathrm{d} \tau -$$ +```math +\langle i_L \rangle(t) = \langle i_L \rangle(t - \Delta t) + \int_{t - \Delta t}^t \frac{1}{L} \langle v_L \rangle(\tau) - j \omega \ \langle i_L \rangle(\tau) \mathrm{d} \tau +``` Applying the trapezoidal method leads to the finite difference equation: -$$ + +```math \begin{split} - \langle i_L \rangle(k) = \langle i_L \rangle(k-1) + \frac{\Delta t}{2} \bigg[ \frac{1}{L} (\langle v_L \rangle(k) + \langle v_L \rangle(k-1)) - - j \omega (\langle i_L \rangle(t) + \langle i_L \rangle(k-1) \bigg] + \langle i_L \rangle(k) = \langle i_L \rangle(k-1) + \frac{\Delta t}{2} \bigg[ \frac{1}{L} (\langle v_L \rangle(k) + \langle v_L \rangle(k-1)) + - j \omega (\langle i_L \rangle(t) + \langle i_L \rangle(k-1) \bigg] \end{split} -$$ +``` Solving this for $\langle i_L \rangle(k)$ results in the \ac{DP} equivalent circuit model: -$$ - \langle i_L \rangle(k) = \frac{a - jab}{1 + b^2} \langle v_L \rangle(k) + \langle i_{L,equiv} \rangle(k-1) -$$ + +```math +\langle i_L \rangle(k) = \frac{a - jab}{1 + b^2} \langle v_L \rangle(k) + \langle i_{L,equiv} \rangle(k-1) +``` + with -$$ - a = \frac{\Delta t}{2L}, \qquad b = \frac{\Delta t \omega}{2} -$$ -$$ - \langle i_{L,equiv} \rangle(k-1) = \frac{1 - b^2 - j2b}{1 + b^2} \langle i_L \rangle(k-1) + \frac{a - jab}{1 + b^2} \langle v_L \rangle(k-1) -$$ -### Capacitance +```math +a = \frac{\Delta t}{2L}, \qquad b = \frac{\Delta t \omega}{2} +``` + +```math +\langle i_{L,equiv} \rangle(k-1) = \frac{1 - b^2 - j2b}{1 + b^2} \langle i_L \rangle(k-1) + \frac{a - jab}{1 + b^2} \langle v_L \rangle(k-1) +``` + +## Capacitance Similarly, a capacitance is described by as follows -$$ - \langle i_C \rangle(k) = C \ \frac{\mathrm{d} \langle v_C \rangle}{\mathrm{d} t} + j \omega C \ \langle v_C \rangle(t) -$$ -$$ - v_C(t) = v_C(t- \Delta t) + \int_{t- \Delta t}^{t} \frac{1}{C} \ i_C(\tau) -j \omega \ v_C(\tau) \ \mathrm{d} \tau -$$ + +```math +\langle i_C \rangle(k) = C \ \frac{\mathrm{d} \langle v_C \rangle}{\mathrm{d} t} + j \omega C \ \langle v_C \rangle(t) +``` + +```math +v_C(t) = v_C(t- \Delta t) + \int_{t- \Delta t}^{t} \frac{1}{C} \ i_C(\tau) -j \omega \ v_C(\tau) \ \mathrm{d} \tau +``` Applying the trapezoidal rule for the capacitance equation leads to the finite difference equation: + ```math \begin{split} \langle v_C \rangle(k) = \langle v_C \rangle(k-1) + \frac{\Delta t}{2} \bigg[ \frac{1}{C} \ \langle i_C \rangle(k) - j \omega \ \langle v_C \rangle(k) \\ + \frac{1}{C} \ \langle i_C \rangle(k-1) - j \omega \ \langle v_C \rangle(k-1) \bigg] - \end{split} +\end{split} ``` The DP model for the capacitance is defined by -$$ - \langle i_C \rangle(k) = \frac{1+jb}{a} \ \langle v_C \rangle(k) + \langle i_{C,equiv} \rangle(k-1) -$$ + +```math +\langle i_C \rangle(k) = \frac{1+jb}{a} \ \langle v_C \rangle(k) + \langle i_{C,equiv} \rangle(k-1) +``` + with -$$ - a = \frac{\Delta t}{2C}, \qquad - b = \frac{\Delta t \omega}{2} -$$ -$$ - \langle i_{C,equiv} \rangle(k-1) = - \frac{1-jb}{a} \ \langle v_C \rangle(k-1) - \langle i_C \rangle(k-1) -$$ -### RL-series element +```math +a = \frac{\Delta t}{2C}, \qquad +b = \frac{\Delta t \omega}{2} +``` + +```math +\langle i_{C,equiv} \rangle(k-1) = - \frac{1-jb}{a} \ \langle v_C \rangle(k-1) - \langle i_C \rangle(k-1) +``` + +## RL-series element In dynamic phasors the integration of the inductance equation yields -$$ - \langle v \rangle(t) = L \frac{\mathrm{d}}{dt} \langle i \rangle(t) + j \omega L \ \langle i \rangle(t) + R \ \langle i \rangle(t) -$$ -$$ - \langle i \rangle(t) = \langle i \rangle(t - \Delta t) + \int_{t - \Delta t}^t \frac{1}{L} \langle v \rangle(\tau) - j \omega \ \langle i \rangle(\tau) - \frac{R}{L} \ \langle i \rangle(\tau) \mathrm{d} \tau -$$ + +```math +\langle v \rangle(t) = L \frac{\mathrm{d}}{dt} \langle i \rangle(t) + j \omega L \ \langle i \rangle(t) + R \ \langle i \rangle(t) +``` + +```math +\langle i \rangle(t) = \langle i \rangle(t - \Delta t) + \int_{t - \Delta t}^t \frac{1}{L} \langle v \rangle(\tau) - j \omega \ \langle i \rangle(\tau) - \frac{R}{L} \ \langle i \rangle(\tau) \mathrm{d} \tau +``` Applying the trapezoidal method leads to the finite difference equation: -$$ + +```math \begin{split} - \langle i \rangle(k) = \langle i \rangle(k-1) + \frac{\Delta t}{2} \bigg[ \frac{1}{L} (\langle v \rangle(k) + \langle v \rangle(k-1)) - - \left( j \omega + \frac{R}{L} \right) (\langle i \rangle(k) + \langle i \rangle(k-1)) \bigg] +\langle i \rangle(k) = \langle i \rangle(k-1) + \frac{\Delta t}{2} \bigg[ \frac{1}{L} (\langle v \rangle(k) + \langle v \rangle(k-1)) + - \left( j \omega + \frac{R}{L} \right) (\langle i \rangle(k) + \langle i \rangle(k-1)) \bigg] \end{split} -$$ +``` Solving this for $\langle i \rangle(k)$ results in the \ac{DP} equivalent circuit model: -$$ - \langle i \rangle(k) = \frac{a + Ra^2 - jab}{(1+Ra)^2 + b^2} \langle v \rangle(k) + \langle i_{equiv} \rangle(k-1) -$$ + +```math +\langle i \rangle(k) = \frac{a + Ra^2 - jab}{(1+Ra)^2 + b^2} \langle v \rangle(k) + \langle i_{equiv} \rangle(k-1) +``` + with -$$ - a = \frac{\Delta t}{2L}, \qquad b = \frac{\Delta t \omega}{2} -$$ -$$ - \langle i_{equiv} \rangle(k-1) = \frac{1 - b^2 - j2b + 2Ra + (Ra)^2 - j2Rab}{(1+Ra^2) + b^2} \langle i \rangle(k-1) + \frac{a + Ra^2 - jab}{(1+Ra)^2 + b^2} \langle v \rangle(k-1) -$$ \ No newline at end of file + +```math +a = \frac{\Delta t}{2L}, \qquad b = \frac{\Delta t \omega}{2} +``` + +```math +\langle i_{equiv} \rangle(k-1) = \frac{1 - b^2 - j2b + 2Ra + (Ra)^2 - j2Rab}{(1+Ra^2) + b^2} \langle i \rangle(k-1) + \frac{a + Ra^2 - jab}{(1+Ra)^2 + b^2} \langle v \rangle(k-1) +``` diff --git a/docs/hugo/content/en/docs/Models/Synchronous Generator/index.md b/docs/hugo/content/en/docs/Models/Synchronous Generator/index.md index d711b19343..aca6e7a3cb 100644 --- a/docs/hugo/content/en/docs/Models/Synchronous Generator/index.md +++ b/docs/hugo/content/en/docs/Models/Synchronous Generator/index.md @@ -11,17 +11,19 @@ Two different synchronous machine models are currently available: The machine model is interfaced to the nodal analysis network solver through a current source, which only affects the source vector and not the system matrix [Wang2010](https://ieeexplore.ieee.org/document/5411963). -## Basic Equations +# Basic Equations The equations of the stator and rotor voltages are + ```math \begin{align} - \mathbf{v}_{abcs} &= \mathbf{R}_s \mathbf{i}_{abcs} + \frac{d}{dt} \boldsymbol{\lambda}_{abcs} \\ - \mathbf{v}_{dqr} &= \mathbf{R}_r \mathbf{i}_{dqr} + \frac{d}{dt} \boldsymbol{\lambda}_{dqr} + \mathbf{v}_{abcs} &= \mathbf{R}_s \mathbf{i}_{abcs} + \frac{d}{dt} \boldsymbol{\lambda}_{abcs} \\ + \mathbf{v}_{dqr} &= \mathbf{R}_r \mathbf{i}_{dqr} + \frac{d}{dt} \boldsymbol{\lambda}_{dqr} \end{align} ``` where + ```math \begin{align} \mathbf{v}_{abcs} &= @@ -67,20 +69,21 @@ where ``` The flux linkage equations are defined as + ```math \begin{equation} - \begin{bmatrix} - \boldsymbol{\lambda}_{abcs} \\ - \boldsymbol{\lambda}_{dqr} - \end{bmatrix} - = - \begin{bmatrix} - \mathbf{L}_s & \mathbf{L}_{rs} \\ - {(\mathbf{L}_{rs})}^{T} & \mathbf{L}_r - \end{bmatrix} - \begin{bmatrix} - \mathbf{i}_{abcs} \\ - \mathbf{i}_{dqr} + \begin{bmatrix} + \boldsymbol{\lambda}_{abcs} \\ + \boldsymbol{\lambda}_{dqr} + \end{bmatrix} + = + \begin{bmatrix} + \mathbf{L}_s & \mathbf{L}_{rs} \\ + {(\mathbf{L}_{rs})}^{T} & \mathbf{L}_r + \end{bmatrix} + \begin{bmatrix} + \mathbf{i}_{abcs} \\ + \mathbf{i}_{dqr} \end{bmatrix} \end{equation} ``` @@ -88,6 +91,7 @@ The flux linkage equations are defined as The inductance matrices are varying with the rotor position $\theta_r$ which varies with time. The mechanical equations are: + ```math \begin{align} \frac{d\theta_r}{dt} &= \omega_r \\ @@ -107,6 +111,7 @@ For stator referred variables, the base quantities for per unit are chosen as fo - $f_{base}$ rated frequency in Hz The synchronous generator equations in terms of per unit values in the rotor reference frame become: + ```math \begin{equation} \begin{bmatrix} @@ -132,7 +137,9 @@ The synchronous generator equations in terms of per unit values in the rotor ref \end{bmatrix} \end{equation} ``` + where + ```math \begin{align} \mathbf{v}_{dq0s} &= @@ -161,7 +168,9 @@ where \end{pmatrix}^T. \end{align} ``` + The flux linkages are: + ```math \begin{equation} \begin{pmatrix} @@ -179,7 +188,9 @@ The flux linkages are: \end{pmatrix} \end{equation} ``` + where + ```math \begin{align} \mathbf{L}_{dqss} &= @@ -213,7 +224,9 @@ where \end{bmatrix} \nonumber \\ \end{align} ``` + with + ```math \begin{align} L_{d} &= L_{ls} + L_{md} \nonumber \\ @@ -226,6 +239,7 @@ with ``` The mechanical equations in per unit become: + ```math \begin{align} T_e &= \lambda_{qs} i_{ds} - \lambda_{ds} i_{qs} \\ @@ -233,16 +247,20 @@ The mechanical equations in per unit become: \frac{1}{\omega_b} \frac{d \omega_r}{dt} &= \frac{1}{2H} (T_m - T_e). \end{align} ``` + For the simulation, fluxes are chosen as state variables. To avoid the calculation of currents from fluxes using the inverse of the inductance matrix, the equation set needs to be solved for the fluxes analytically. To simplify the calculations, dq axis magnetizing flux linkages are defined [Krause, Analysis of electric machinery and drive systems, 2002]: + ```math \begin{align} \lambda_{md} &= L_{md} \left( i_{ds} + i_{fd} + i_{kd} \right) \nonumber \\ \lambda_{mq} &= L_{mq} \left( i_{qs} + i_{kq1} + i_{kq2} \right) \end{align} ``` + Using the flux linkages results in a simpler equation set for the fluxes: + ```math \begin{align} \lambda_{ds} &= L_{ls} i_{ds} + L_{md} \left( i_{ds} + i_{fd} + i_{kd} \right) \nonumber \\ @@ -254,6 +272,7 @@ Using the flux linkages results in a simpler equation set for the fluxes: \lambda_{kq2} &= L_{ls} i_{kq2} + L_{mq} \left( i_{qs} + i_{kq1} + i_{kq2} \right) \end{align} ``` + ```math \begin{align} \lambda_{ds} &= L_{ls} i_{ds} + \lambda_{md} \nonumber \\ @@ -272,6 +291,7 @@ The fundamental dynamic phasors are similar to the dq0 quantities for symmetrica The network abc dynamic phasor quantities can be converted to dq0 dynamic phasors by applying the symmetrical components transformation and a rotation. The angle $\delta$ is the orientation of the dq0 reference frame relative to the abc frame. + ```math \begin{align} \langle i_{ds} \rangle_{0} &= \mathbf{Re} \left\{ \langle i_{p} \rangle_1 \ \mathrm{e}^{-j \delta} \right\} \nonumber \\ @@ -281,7 +301,9 @@ The angle $\delta$ is the orientation of the dq0 reference frame relative to the \langle i_{0s} \rangle_{1} &= \mathbf{Re} \left\{ \langle i_{z} \rangle_1 \right\} \end{align} ``` + The winding currents for positive and zero sequence components can be expressed as + ```math \begin{align} \langle i_{ds} \rangle_0 &= \frac{\langle \lambda_{ds} \rangle_0 - \langle \lambda_{md} \rangle_0 }{L_{ls}} \nonumber \\ @@ -293,6 +315,7 @@ The winding currents for positive and zero sequence components can be expressed \langle i_{kq2} \rangle_0 &= \frac{\langle \lambda_{kq2} \rangle_0 - \langle \lambda_{mq} \rangle_0}{L_{lkq2}}. \end{align} ``` + ```math \begin{align} \frac{d}{dt} \langle \lambda_{ds} \rangle_0 &= \langle v_{ds} \rangle_0 + \langle \omega_r \rangle_0 \langle \lambda_{qs} \rangle_0 + \frac{R_s}{L_{ls}} \left( \langle \lambda_{md} \rangle_0 - \langle \lambda_{ds} \rangle_0 \right) \nonumber \\ @@ -304,22 +327,28 @@ The winding currents for positive and zero sequence components can be expressed \frac{d}{dt} \langle \lambda_{kq2} \rangle_0 &= \frac{R_{kq2}}{L_{lkq2}} \left( \langle \lambda_{mq} \rangle_0 - \langle \lambda_{kq2} \rangle_0 \right). \end{align} ``` + In the dynamic phasor case, the equation for $\frac{d}{dt} \langle \lambda_{0s} \rangle_1$ has a frequency shift. To complete the state model, the magnetizing flux linkages are expressed as: + ```math \begin{align} \langle \lambda_{md} \rangle_0 &= L_{ad} \left( \frac{\langle \lambda_{ds} \rangle_0}{L_{ls}} + \frac{\langle \lambda_{fd} \rangle_0}{L_{lfd}} + \frac{\langle \lambda_{kd} \rangle_0}{L_{lkd}} \right) \nonumber \\ \langle \lambda_{mq} \rangle_0 &= L_{aq} \left( \frac{\langle \lambda_{qs} \rangle_0}{L_{ls}} + \frac{\langle \lambda_{kq1} \rangle_0}{L_{lkq1}} + \frac{\langle \lambda_{kq2} \rangle_0}{L_{lkq2}} \right) \end{align} ``` + where + ```math \begin{align} L_{ad} &= \left( \frac{1}{L_{md}} + \frac{1}{L_{ls}} + \frac{1}{L_{lfd}} + \frac{1}{L_{lkd}} \right) \nonumber \\ L_{aq} &= \left( \frac{1}{L_{mq}} + \frac{1}{L_{ls}} + \frac{1}{L_{lkq1}} + \frac{1}{L_{lkq2}} \right). \end{align} ``` + The mechanical equations in dynamic phasors are: + ```math \begin{align} T_e &= \langle \lambda_{qs} \rangle_0 \langle i_{ds} \rangle_0 - \langle \lambda_{ds} \rangle_0 \langle i_{qs} \rangle_0 \\ diff --git a/docs/hugo/content/en/docs/Models/Transformer/index.md b/docs/hugo/content/en/docs/Models/Transformer/index.md index 4414883c63..56a331c27f 100644 --- a/docs/hugo/content/en/docs/Models/Transformer/index.md +++ b/docs/hugo/content/en/docs/Models/Transformer/index.md @@ -4,7 +4,8 @@ linkTitle: "Transformer" date: 2021-07-22 --- -## 2-Winding Transformer +# 2-Winding Transformer + The transformer model is composed of an RL-segment and an ideal transformer. The single line diagram is depicted in the figure below. @@ -13,7 +14,7 @@ The single line diagram is depicted in the figure below. If node reduction is not applied, two virtual nodes are created to stamp this model into the system matrix. Furthermore, the ideal transformer has an additional equation, which requires an extension of the system matrix. -The complete matrix stamp for the ideal transformer is +The complete matrix stamp for the ideal transformer is ```math \begin{array}{c|c c c} @@ -33,10 +34,10 @@ i_{l} \cr \cr \cr 0\cr -\end{pmatrix} +\end{pmatrix} ``` The variable $j$ denotes the high voltage node while $k$ is the low voltage node. $l$ indicates the inserted row and column to accommodate the relation between the two voltages at the ends of the transformer. The transformer ratio is defined as $T = V_{j} / V_{k}$. -A phase shift can be introduced if $T$ is considered as a complex number. \ No newline at end of file +A phase shift can be introduced if $T$ is considered as a complex number. diff --git a/docs/hugo/content/en/docs/Models/_index.md b/docs/hugo/content/en/docs/Models/_index.md index 2cbb1cb5fa..89f479905a 100644 --- a/docs/hugo/content/en/docs/Models/_index.md +++ b/docs/hugo/content/en/docs/Models/_index.md @@ -7,22 +7,23 @@ description: > --- The following models are currently available: + - Dynamic phasors - - inductor, capacitor, resistor - - current and voltage source - - load (PQ and Z type) - - pi-line - - transmission line (Bergeron) - - synchronous generator dq-frame full order (Kundur, Krause) - - inverter averaged - - inverter with harmonics (comparable to switched model) - - switch + - inductor, capacitor, resistor + - current and voltage source + - load (PQ and Z type) + - pi-line + - transmission line (Bergeron) + - synchronous generator dq-frame full order (Kundur, Krause) + - inverter averaged + - inverter with harmonics (comparable to switched model) + - switch - EMT - - inductor, capacitor, resistor - - current and voltage source - - load (Z type) - - pi-line - - transmission line (Bergeron) - - synchronous generator dq-frame full order (Kundur, Krause) - - inverter averaged - - switch + - inductor, capacitor, resistor + - current and voltage source + - load (Z type) + - pi-line + - transmission line (Bergeron) + - synchronous generator dq-frame full order (Kundur, Krause) + - inverter averaged + - switch diff --git a/docs/hugo/content/en/docs/Models/branches.md b/docs/hugo/content/en/docs/Models/branches.md index e3419eaeab..946237210b 100644 --- a/docs/hugo/content/en/docs/Models/branches.md +++ b/docs/hugo/content/en/docs/Models/branches.md @@ -4,8 +4,8 @@ linkTitle: "Branches" date: 2020-03-18 --- -## RX-Line +# RX-Line -## PI-Line +# PI-Line -## Transformer +# Transformer diff --git a/docs/hugo/content/en/docs/Models/power-electronics.md b/docs/hugo/content/en/docs/Models/power-electronics.md index 4318ad91f8..14fa055ddd 100644 --- a/docs/hugo/content/en/docs/Models/power-electronics.md +++ b/docs/hugo/content/en/docs/Models/power-electronics.md @@ -2,4 +2,4 @@ title: "VS-Inverter" linkTitle: "VS-Inverter" date: 2020-03-18 ---- \ No newline at end of file +--- diff --git a/docs/hugo/content/en/docs/Overview/Architecture/index.md b/docs/hugo/content/en/docs/Overview/Architecture/index.md index da22567da7..30bce46db2 100644 --- a/docs/hugo/content/en/docs/Overview/Architecture/index.md +++ b/docs/hugo/content/en/docs/Overview/Architecture/index.md @@ -5,7 +5,7 @@ weight: 1 date: 2020-03-25 --- -## Modules and Dependencies +# Modules and Dependencies The figure below shows the main components of the DPsim library and their dependencies on other software projects. All functionality is implemented in the C++ core, which can be used standalone or together with the Python interface. @@ -35,7 +35,7 @@ Its main purpose will be offline simulation, for example, to provide reference r The component models depend mostly on the Eigen library. Even if components are used in combination with Sundials ODE / DAE solvers, we try to keep the specific functions required by these solvers independent of the Sundials package. -## Class Hierarchy +# Class Hierarchy The `Simulation` class holds references to instances of `Interface`, `Solver`, `Logger` and `SystemTopology`. For a simulation scenario, the minimum description would include a `SystemTopology` and a solver type. diff --git a/docs/hugo/content/en/docs/Overview/Attributes/index.md b/docs/hugo/content/en/docs/Overview/Attributes/index.md index cf36222e54..8469ebb29c 100644 --- a/docs/hugo/content/en/docs/Overview/Attributes/index.md +++ b/docs/hugo/content/en/docs/Overview/Attributes/index.md @@ -12,19 +12,20 @@ In general, attributes are instances of the `Attribute` class, but they are u Through the template parameter `T` of the `Attribute` class, attributes can have different value types, most commonly `Real`, `Complex`, `Matrix`, or `MatrixComp`. Additionally, attributes can fall into one of two categories: **Static** attributes have a fixed value which can only be changed explicitly through the attribute's `set`-method or through a mutable reference obtained through `get`. -**Dynamic** attributes on the other hand can dynamically re-compute their value from other attributes every time they are read. This can for example be used to create a scalar attribute of type `Real` whose value always contains the magnitude of another, different attribute of type `Complex`. +**Dynamic** attributes on the other hand can dynamically re-compute their value from other attributes every time they are read. This can for example be used to create a scalar attribute of type `Real` whose value always contains the magnitude of another, different attribute of type `Complex`. Any simulation component or class which inherits from `IdentifiedObject` contains an instance of an `AttributeList`. This list can be used to store all the attributes present in this component and later access them via a `String` instead of having to use the member variable directly. -For reasons of code clarity and runtime safety, the member variables should still be used whenever possible. +For reasons of code clarity and runtime safety, the member variables should still be used whenever possible. + +# Creating and Storing Attributes -## Creating and Storing Attributes Normally, a new attribute is created by using the `create` or `createDynamic` method of an `AttributeList` object. These two methods will create a new attribute of the given type and insert it into the `AttributeList` under the given name. After the name, `create` can take an additional parameter of type `T` which will be used as the initial value for this attribute. Afterwards, a pointer to the attribute is returned which can then be stored in a component's member variable. Usually this is done in the component's constructor in an initialization list: -```cpp +```cpp /// Component class Base::Ph1::PiLine public: @@ -47,19 +48,20 @@ When a class has no access to an `AttributeList` object (for example the `Simula ```cpp // Simulation class -Simulation::Simulation(String name, Logger::Level logLevel) : - mName(AttributeStatic::make(name)), - mFinalTime(AttributeStatic::make(0.001)), - mTimeStep(AttributeStatic::make(0.001)), - mSplitSubnets(AttributeStatic::make(true)), - mSteadyStateInit(AttributeStatic::make(false)), - //... +Simulation::Simulation(String name, Logger::Level logLevel) : + mName(AttributeStatic::make(name)), + mFinalTime(AttributeStatic::make(0.001)), + mTimeStep(AttributeStatic::make(0.001)), + mSplitSubnets(AttributeStatic::make(true)), + mSteadyStateInit(AttributeStatic::make(false)), + //... { - // ... + // ... } ``` -## Working with Static Attributes +# Working with Static Attributes + As stated above, the value of a static attribute can only be changed through the attribute's `set`-method or by writing its value through a mutable reference obtained by calling `get`. This means that the value will not change between consecutive reads. Because of the performance benefits static attributes provide over dynamic attributes, attributes should be static whenever possible. @@ -73,6 +75,7 @@ Real& read3 = **attr; //read3 = 0.001 ``` The value of an attribute can be changed by either writing to the mutable reference obtained from `get`, or by calling the `set`-method: + ```cpp AttributeBase::Ptr attr = AttributeStatic::make(0.001); Real read1 = **attr; //read1 = 0.001 @@ -82,12 +85,14 @@ attr->set(0.003); Real read3 = **attr; //read3 = 0.003 ``` -## Working with Dynamic Attributes -In general, dynamic attributes can be accessed via the same `get` and `set`-methods described above for static attributes. However, +# Working with Dynamic Attributes + +In general, dynamic attributes can be accessed via the same `get` and `set`-methods described above for static attributes. However, dynamic attributes can additionally have **dependencies** on other attributes which affect the behavior of these methods. Usually, this is used to dynamically compute the attribute's value from the value of another attribute. In the simplest case, a dynamic attribute can be set to **reference** another (static or dynamic) attribute using the `setReference`-method. After this method has been called, the dynamic attribute's value will always reflect the value of the attribute it references: + ```cpp AttributeBase::Ptr attr1 = AttributeStatic::make(0.001); AttributeBase::Ptr attr2 = AttributeDynamic::make(); @@ -101,6 +106,7 @@ Real read2 = **attr2; //read2 = 0.002 When working with references between multiple dynamic attributes, the direction in which the references are defined can be important: References should always be set in such a way that the reference relationships form a one-way chain. Only the last attribute in such a reference chain (which itself does not reference anything) should be modified by external code (i.e. through mutable references or the `set`-method). This ensures that changes are always reflected in all attributes in the chain. For example, the following setup might lead to errors because it overwrites an existing reference: + ```cpp // Overwriting an existing reference relationship AttributeBase::Ptr A = AttributeDynamic::make(); @@ -130,18 +136,21 @@ C->setReference(B); // Current chain: C -> B -> A Aside from setting references, it is also possible to completely recompute a dynamic attribute's value every time it is read. This can for example be used to create attributes which reference a single matrix coefficient of another attribute, or which represent the magnitude or phase of a complex attribute. Dynamic attributes which depend on one other attribute in this way are also called **derived** attributes, and they can be created by calling one of the various `derive...` methods on the original attribute: + ```cpp AttributeBase::Ptr attr1 = AttributeStatic::make(Complex(3, 4)); AttributeBase::Ptr attr2 = attr1->deriveMag(); -Real read1 = **attr2; //read1 = 5 +Real read1 = **attr2; // read1 = 5 **attr1 = Complex(1, 0); -Real read2 = **attr2; //read2 = 1 +Real read2 = **attr2; // read2 = 1 ``` + There is also a general `derive`-method which can take a custom `getter` and `setter` lambda function for computing the derived attribute from its dependency. For more complex cases involving dependencies on multiple attributes, the `AttributeDynamic` class has a method called `addTask` which can be used to add arbitrary computation tasks which are executed when the attribute is read or written to. For more information, check the method comments in `Attribute.h`. -## Using Attributes for Logging and Interfacing +# Using Attributes for Logging and Interfacing + When setting up a simulation, there are some methods which require an instance of `AttributeBase::Ptr` as a parameter. Examples for this are the logger methods (e.g. `DataLogger::logAttribute`) and [interface]({{< ref "../interfaces.md" >}}) methods (e.g. `InterfaceVillas::exportAttribute`). To obtain the required attribute pointer, one can either directly access the public member variables of the component the attribute belongs to, or use the component's `attribute(String name)` method which will look up the attribute in the component's `AttributeList`: @@ -164,6 +173,7 @@ intf->exportAttribute(r1->mIntfVoltage->deriveCoeff(0, 0), 0, true); ``` When creating a simulation in Python, the component's member variables are usually not accessible, so the `attr`-method has to be used for all accesses: + ```python # dpsim-mqtt.py intf = dpsimpyvillas.InterfaceVillas(name='dpsim-mqtt', config=mqtt_config) @@ -171,7 +181,7 @@ intf.import_attribute(evs.attr('V_ref'), 0, True) intf.export_attribute(r12.attr('i_intf').derive_coeff(0, 0), 0) ``` -## Using Attributes to Schedule Tasks +# Using Attributes to Schedule Tasks Attributes are also used to determine dependencies of tasks on data, which is information required by the scheduler. For the usual `MNAPreStep` and `MNAPostStep` tasks, these dependencies are configured in the `mnaAddPreStepDependencies` and `mnaAddPostStepDependencies` methods: @@ -182,9 +192,10 @@ void DP::Ph1::Inductor::mnaAddPostStepDependencies( AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector ) { attributeDependencies.push_back(leftVector); - modifiedAttributes.push_back(mIntfVoltage); - modifiedAttributes.push_back(mIntfCurrent); + modifiedAttributes.push_back(mIntfVoltage); + modifiedAttributes.push_back(mIntfCurrent); } ``` + Here, the MNA post step depends on the solution vector of the system, `leftVector`, and modifies `mIntfVoltage` and `mIntfCurrent`. -Therefore, this task needs to be scheduled after the system solution that computes `leftVector` and before tasks that require the voltage and current interface vectors of the inductance, e.g. the task logging these values. \ No newline at end of file +Therefore, this task needs to be scheduled after the system solution that computes `leftVector` and before tasks that require the voltage and current interface vectors of the inductance, e.g. the task logging these values. diff --git a/docs/hugo/content/en/docs/Overview/Scheduling/index.md b/docs/hugo/content/en/docs/Overview/Scheduling/index.md index 2214830e87..3ecd7840d7 100644 --- a/docs/hugo/content/en/docs/Overview/Scheduling/index.md +++ b/docs/hugo/content/en/docs/Overview/Scheduling/index.md @@ -12,4 +12,4 @@ In the simplest case, all tasks of a level have to be finished before tasks of t ![image](task_graph_levels.svg) The dependencies of tasks on data are determined by referencing the attributes that are read or modified by the task. -The scheduler computes the schedule prior to the simulation from the task dependency graph resulting from the tasks' data dependencies. \ No newline at end of file +The scheduler computes the schedule prior to the simulation from the task dependency graph resulting from the tasks' data dependencies. diff --git a/docs/hugo/content/en/docs/Overview/_index.md b/docs/hugo/content/en/docs/Overview/_index.md index 6638d4666d..e754419a2a 100644 --- a/docs/hugo/content/en/docs/Overview/_index.md +++ b/docs/hugo/content/en/docs/Overview/_index.md @@ -12,12 +12,11 @@ Users interact with the C++ simulation kernel via Python bindings, which can be The DPsim simulation kernel is implemented in C++ and uses the Eigen linear algebra library. By using a system programming language like C++ and a highly optimized math library, optimal performance and real-time execution can be guaranteed. The integration into the [VILLASframework](https://github.com/VILLASframework/node) allows DPsim to be used in large-scale co-simulations. -## Licensing +# Licensing The project is released under the terms of the [MPL 2.0](https://mozilla.org/MPL/2.0/). -## Where should I go next? +# Where should I go next * [Getting Started]({{< ref "/docs/Getting Started/" >}} "Getting Started"): Get started with DPsim * [Examples]({{< ref "/docs/Examples/" >}} "Examples"): Check out some example code! - diff --git a/docs/hugo/content/en/docs/Overview/interfaces.md b/docs/hugo/content/en/docs/Overview/interfaces.md index f1086cfa97..d8731b19da 100644 --- a/docs/hugo/content/en/docs/Overview/interfaces.md +++ b/docs/hugo/content/en/docs/Overview/interfaces.md @@ -10,7 +10,7 @@ Interfaces are subclasses of `Interface` and implement the methods `addExport` a This way, attributes that are imported are read from the interface before they are used in any DPsim component. Attributes that are exported are written to the interface after they are set by a DPsim component. -## Interfacing with VILLASnode +# Interfacing with VILLASnode > This feature requires the compilation of DPsim with the `WITH_VILLAS` feature flag. For use of the VILLASnode interface in python, the `dpsimpyvillas` target has to built in addition to the normal `dpsimpy` package. @@ -38,6 +38,7 @@ The attributes given as the first parameter to these methods are attributes belo As an example, for exporting and importing attributes via the MQTT protocol, the VILLASnode interfaces can be configured as follows: Using C++: + ```cpp // JSON configuration adhering to the VILLASnode documentation std::string mqttConfig = R"STRING({ @@ -61,6 +62,7 @@ intf->exportAttribute(r12->mIntfCurrent->deriveCoeff(0, 0), 1, true, "v ``` Using Python: + ```python # JSON configuration adhering to the VILLASnode documentation mqtt_config = '''{ @@ -83,8 +85,10 @@ intf.import_attribute(evs.attr('V_ref'), 0, True) intf.export_attribute(r12.attr('i_intf').derive_coeff(0, 0), 0) ``` -## Adding an Interface to the Simulation +# Adding an Interface to the Simulation + After a new interface has been created and configured, it can be added to a simulation using the `Simulation::addInterface` method: + ```cpp // Create and configure simulation RealTimeSimulation sim(simName); @@ -105,11 +109,13 @@ Note that the execution of these tasks might not necessarily coincide with the p This is because the interface internally spawns two new threads for exchanging data with the environment and then uses a **lock-free queue** for communication between these reader and writer threads, and the simulation. Because of this, time-intensive import or export operations will not block the main simulation thread unless this is explicitly configured in the interface's `importAttribute` and `exportAttribute` methods. -## Synchronizing the Simulation with the Environment +# Synchronizing the Simulation with the Environment + To allow for synchronizing the DPsim simulation with external services, the `Interface` class provides some additional configuration options in the `importAttribute` and `exportAttribute` methods. For imports, setting the `blockOnRead` parameter will completely halt the simulation at the start of every time step until a new value for this attribute was read from the environment. Additionally, the `syncOnSimulationStart` parameter can be set for every import to indicate that this attribute is used to synchronize the start of the simulation. When a simulation contains any interfaces importing attributes which have `syncOnSimulationStart` set, the `Simulation::sync` will be called before the first time step. This method will: + - write out all attributes configured for export to the environment - block until all attributes with `syncOnSimulationStart` set have been read from the environment at least once - write out all exported attributes again diff --git a/docs/hugo/content/en/docs/Overview/mnainterface.md b/docs/hugo/content/en/docs/Overview/mnainterface.md index d7a2d5a527..21eb04e1c3 100644 --- a/docs/hugo/content/en/docs/Overview/mnainterface.md +++ b/docs/hugo/content/en/docs/Overview/mnainterface.md @@ -26,9 +26,10 @@ virtual void mnaCompApplySystemMatrixStampHarm(SparseMatrixRow& systemMatrix, In virtual void mnaCompApplyRightSideVectorStampHarm(Matrix& sourceVector); virtual void mnaCompApplyRightSideVectorStampHarm(Matrix& sourceVector, Int freqIdx); ``` + `MNASimPowerComp` provides empty default implementations for all of these methods, so component classes are not forced to implement any of them. -## Controlling Common Base Class Behavior +# Controlling Common Base Class Behavior Child component classes can control the behavior of the base class through the constructor arguments of `MNASimPowerComp`. The two boolean variables `hasPreStep` and `hasPostStep` can be used to control whether the `MNAPreStep` and `MNAPostStep` tasks will be created and registered. @@ -40,10 +41,10 @@ If this behavior is not desired, e.g. for resistors which have no influence on t ```cpp void DP::Ph1::Resistor::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { - updateMatrixNodeIndices(); + updateMatrixNodeIndices(); - **mRightVector = Matrix::Zero(0, 0); - //... + **mRightVector = Matrix::Zero(0, 0); + //... } ``` diff --git a/docs/hugo/content/en/docs/Overview/subcomponents.md b/docs/hugo/content/en/docs/Overview/subcomponents.md index 437ae1af89..936bbdeb1e 100644 --- a/docs/hugo/content/en/docs/Overview/subcomponents.md +++ b/docs/hugo/content/en/docs/Overview/subcomponents.md @@ -7,7 +7,8 @@ date: 2022-12-14 In DPsim, there are many components which can be broken down into individual subcomponents. Examples are the `PiLine`, consisting of an inductor, three resistors, and two capacitors, or the `NetworkInjection` which contains a voltage source. On the C++ class level, these subcomponents are represented by member variables within the larger component class. In this guide, all components which have subcomponents are called **composite components**. -## Creating Composite Components +# Creating Composite Components + While normal components are usually subclasses of `SimPowerComp` or `MNASimPowerComp`, there exists a special base class for composite components called `CompositePowerComp`. This class provides multiple methods and parameters for configuring how the subcomponents should be handled with respect to the `MNAPreStep` and `MNAPostStep` tasks. @@ -17,39 +18,41 @@ be set to automatically create and register a `MNAPreStep` or `MNAPostStep` task Additionally, all subcomponents should be registered as soon as they are created using the `addMNASubComponent`-method. This method takes multiple parameters defining how and in what order the subcomponent's pre- and post- steps should be called, as well as if the subcomponent should be stamped into the system `rightVector`: + ```cpp // DP_Ph1_PiLine.cpp DP::Ph1::PiLine::PiLine(String uid, String name, Logger::Level logLevel) - : Base::Ph1::PiLine(mAttributes), - // Call the constructor of CompositePowerComp and enable automatic pre- and post-step creation - CompositePowerComp(uid, name, true, true, logLevel) + : Base::Ph1::PiLine(mAttributes), + // Call the constructor of CompositePowerComp and enable automatic pre- and post-step creation + CompositePowerComp(uid, name, true, true, logLevel) { - //... + //... } void DP::Ph1::PiLine::initializeFromNodesAndTerminals(Real frequency) { - //... - // Create series sub components - mSubSeriesResistor = std::make_shared(**mName + "_res", mLogLevel); - - // Setup mSubSeriesResistor... - - // Register the resistor as a subcomponent. The resistor's pre- and post-step will be called before the pre- and post-step of the parent, - // and the resistor does not contribute to the `rightVector`. - addMNASubComponent(mSubSeriesResistor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); - - mSubSeriesInductor = std::make_shared(**mName + "_ind", mLogLevel); - - // Setup mSubSeriesInductor... - - // Register the inductor as a subcomponent. The inductor's pre- and post-step will be called before the pre- and post-step of the parent, - // and the inductor does contribute to the `rightVector`. - addMNASubComponent(mSubSeriesInductor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); - //... + //... + // Create series sub components + mSubSeriesResistor = std::make_shared(**mName + "_res", mLogLevel); + + // Setup mSubSeriesResistor... + + // Register the resistor as a subcomponent. The resistor's pre- and post-step will be called before the pre- and post-step of the parent, + // and the resistor does not contribute to the `rightVector`. + addMNASubComponent(mSubSeriesResistor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + mSubSeriesInductor = std::make_shared(**mName + "_ind", mLogLevel); + + // Setup mSubSeriesInductor... + + // Register the inductor as a subcomponent. The inductor's pre- and post-step will be called before the pre- and post-step of the parent, + // and the inductor does contribute to the `rightVector`. + addMNASubComponent(mSubSeriesInductor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + //... } ``` -## Orchestrating MNA Method Calls +# Orchestrating MNA Method Calls + By choosing which methods to override in the composite component class, subcomponent handling can either be offloaded to the `CompositePowerComp` base class or manually implemented in the new component class. By default, `CompositePowerComp` provides all methods demanded by `MNAInterface` in such a way that the subcomponents' MNA-methods are properly called. To also allow for the composite component class to perform further actions in these MNA-methods, there exist multiple methods prefixed with `mnaParent`, e.g. `mnaParentPreStep` or `mnaParentAddPostStepDependencies`. @@ -63,21 +66,23 @@ so the subcomponent method calls have to be performed explicitly if desired. Giv ```cpp void DP::Ph1::PiLine::mnaParentAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) { - // only add the dependencies of the composite component, the subcomponent's dependencies are handled by the base class - prevStepDependencies.push_back(mIntfCurrent); - prevStepDependencies.push_back(mIntfVoltage); - modifiedAttributes.push_back(mRightVector); + // Only add the dependencies of the composite component, the subcomponent's dependencies are handled by the base class + prevStepDependencies.push_back(mIntfCurrent); + prevStepDependencies.push_back(mIntfVoltage); + modifiedAttributes.push_back(mRightVector); } ``` + ```cpp void DP::Ph1::PiLine::mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) { - // manually add pre-step dependencies of subcomponents - for (auto subComp : mSubcomponentsMNA) { - subComp->mnaAddPreStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes); - } - // add pre-step dependencies of component itself - prevStepDependencies.push_back(mIntfCurrent); - prevStepDependencies.push_back(mIntfVoltage); - modifiedAttributes.push_back(mRightVector); + // Manually add pre-step dependencies of subcomponents + for (auto subComp : mSubcomponentsMNA) { + subComp->mnaAddPreStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes); + } + + // Add pre-step dependencies of component itself + prevStepDependencies.push_back(mIntfCurrent); + prevStepDependencies.push_back(mIntfVoltage); + modifiedAttributes.push_back(mRightVector); } -``` \ No newline at end of file +``` diff --git a/docs/hugo/content/en/docs/Reference/index.md b/docs/hugo/content/en/docs/Reference/index.md index 835a7cc76a..3cd4ba5d72 100644 --- a/docs/hugo/content/en/docs/Reference/index.md +++ b/docs/hugo/content/en/docs/Reference/index.md @@ -10,4 +10,4 @@ description: > The [Sphinx documentation](https://sogno-platform.github.io/dpsim/sphinx/about.html) describes the Python API. The [Doxygen documentation](https://sogno-platform.github.io/dpsim/doxygen/index.html) is automatically generated from the C++ code using Doxygen. -It is helpful to understand the general structure of the C++ DPsim core components. \ No newline at end of file +It is helpful to understand the general structure of the C++ DPsim core components. diff --git a/docs/hugo/content/en/docs/Roadmap/index.md b/docs/hugo/content/en/docs/Roadmap/index.md index 532236367f..f306b51510 100644 --- a/docs/hugo/content/en/docs/Roadmap/index.md +++ b/docs/hugo/content/en/docs/Roadmap/index.md @@ -4,33 +4,6 @@ linkTitle: "Roadmap" weight: 8 --- -Short-term planning for new features is done on the GitHub [Project board](https://github.com/orgs/sogno-platform/projects/1). +Short-term planning for new features is done on the GitHub [Project board](https://github.com/orgs/sogno-platform/projects/1). You can also check the [Issues List](https://github.com/sogno-platform/dpsim/issues) or the [Pull Requests](https://github.com/sogno-platform/dpsim/pulls) on GitHub. - -### Under Development - -- Solver - - [ ] CUDA sparse implementation - - [ ] improve online system matrix computation and refactorization to support nonlinear elements in network solution (NICSLU integration) - - [x] merge DAE solver branch -- Interfaces - - [x] reimplement python interface using pybind and expose more models / functionalities - - [x] add python based examples using the VILLASnode interface - - [x] support matpower / pypower format for static simulation -- Tests, Examples, CI - - [x] convert most of the examples to Python and test them against reference results in CI - - [x] convert more gitlab CI jobs to github actions - - [ ] add IEEE39 system to examples -- Models - - [x] VBR generator model - - [ ] SVC - - [ ] add tap-change to transfomer - -### Ideas - -- Solver - - [ ] improve integration of diakoptics solver -- Interfaces - - [ ] implement CIM reader in Python using new pybind interface and cimpy library - diff --git a/docs/hugo/content/en/docs/Tasks/_index.md b/docs/hugo/content/en/docs/Tasks/_index.md index 9902a7449c..a10e29e70e 100644 --- a/docs/hugo/content/en/docs/Tasks/_index.md +++ b/docs/hugo/content/en/docs/Tasks/_index.md @@ -14,4 +14,3 @@ Each task should give the user * What this task accomplishes. * Instructions for the task. If it involves editing a file, running a command, or writing code, provide code-formatted example snippets to show the user what to do! If there are multiple steps, provide them as a numbered list. * If appropriate, links to related concept, tutorial, or example pages. - diff --git a/docs/hugo/content/en/docs/Tasks/add-model.md b/docs/hugo/content/en/docs/Tasks/add-model.md index 0c47fd8f55..18ea03e195 100644 --- a/docs/hugo/content/en/docs/Tasks/add-model.md +++ b/docs/hugo/content/en/docs/Tasks/add-model.md @@ -7,11 +7,11 @@ description: > Extending the simulator with new component or control models. --- -## Add a Component Model +# Add a Component Model In this section we will show the implementation of a new component model by means a three-phase dynamic phasor inductor model. -### C++ OOP +## C++ OOP DPsim implements component models in a sub project called CPowerSystems (CPS) that is located in the *models* folder. This folder is added to the DPsim CMake project. @@ -21,7 +21,7 @@ DPsim supports different types of solvers (MNA, DAE, NRP). Each solver requires certain member functions in the component class to be implemented. These functions are specified by the solver interface classes: ``MNAInterface.h``, ``DAEInterface.h``, etc. -### Directory / Namespace Structure +## Directory / Namespace Structure For the implementation of the new component, we add two new files @@ -33,40 +33,44 @@ The general structure looks as follows. Directories: - DPsim - | - |- Source - |- Include - \ models - |- Source - |- DP - |- EMT - |- Static - \ Signal - |- Include - |- DP - |- EMT - |- Static - \ Signal +```text +DPsim + | + |- Source + |- Include + \ models + |- Source + |- DP + |- EMT + |- Static + \ Signal + |- Include + |- DP + |- EMT + |- Static + \ Signal +``` Namespaces: - CPS::{DP,EMT,Static,Signal}::{Ph1,Ph3}::{Name} +```cpp +CPS::{DP,EMT,Static,Signal}::{Ph1,Ph3}::{Name} +``` -### Attributes +## Attributes Each components has a list of attributes, which has to be specified when creating the components class. TODO: explain attribute system -### Tasks for Pre/Post-step Functions +## Tasks for Pre/Post-step Functions TODO: add example task dependency graph -### Adding the new Component to DPsim +## Adding the new Component to DPsim After finishing the implementation of the new component, it needs to be added to the following files: -- ``models/Include/cps/Components.h`` -- ``models/Source/CMakeLists.txt`` -- ``Sources/Python/Module.cpp`` +- `models/Include/cps/Components.h` +- `models/Source/CMakeLists.txt` +- `Sources/Python/Module.cpp` diff --git a/docs/hugo/content/en/docs/Tasks/create-simulation.md b/docs/hugo/content/en/docs/Tasks/create-simulation.md index 1c3d85335e..523408fe67 100644 --- a/docs/hugo/content/en/docs/Tasks/create-simulation.md +++ b/docs/hugo/content/en/docs/Tasks/create-simulation.md @@ -8,33 +8,39 @@ description: > Here, we will show the implementation of a new simulation scenario defined in C++, which is using DPsim as a library. -## Directory Structure +# Directory Structure In the end, your directory structure should look like as follows: - my-project - |- CMakeLists.txt - |- source - |- my-scenario.cpp - |- dpsim (as submodule) +```text +my-project + |- CMakeLists.txt + |- source + |- my-scenario.cpp + |- dpsim (as submodule) +``` -## CMake File +# CMake File -Your CMakeLists could look like this: +Your `CMakeLists.txt` could look like this: - cmake_minimum_required(VERSION 3.5) - project(my-project CXX) +```cmake +cmake_minimum_required(VERSION 3.5) +project(my-project CXX) - add_subdirectory(dpsim) +add_subdirectory(dpsim) - add_executable(my-scenario source/my-scenario.cpp) - target_link_libraries(my-scenario dpsim) +add_executable(my-scenario source/my-scenario.cpp) +target_link_libraries(my-scenario dpsim) +``` -## Build the Project +# Build the Project The build process is similar to the one of DPsim: - $ cd my-project - $ mkdir build && cd build - $ cmake .. - $ make my-scenario \ No newline at end of file +```shell +cd my-project +mkdir build && cd build +cmake .. +make my-scenario +``` diff --git a/docs/hugo/content/en/docs/_index.md b/docs/hugo/content/en/docs/_index.md index 1903e5849b..c171901706 100644 --- a/docs/hugo/content/en/docs/_index.md +++ b/docs/hugo/content/en/docs/_index.md @@ -17,25 +17,27 @@ DPsim is a solver library for dynamic power system simulation. - It can load models in the IEC61970 Common Information Model (CIM) / Common Grid Model Exchange Standard (CGMES) XML format. - It can be interfaced to a variety of protocols and interfaces via [VILLASnode](https://fein-aachen.org/projects/villas-node/). - -## Connect +# Connect Using or want to use DPsim? Find out more here: +[GitHub Discussions](https://github.com/sogno-platform/dpsim/discussions) - Ask questions, share ideas, and get community support. This is our main point of contact. + [LF Energy Slack](https://slack.lfenergy.org/) - Chat with other users and developers and get help in the **#sogno** or **#sogno-dpsim** channel. -You can also send a direct message to -- Markus Mirz -- Jan Dinkelbach -- Steffen Vogel +For email inquiries, please contact the Institute for Automation of Complex Power Systems (ACS), which coordinates DPsim development: [post_acs@eonerc.rwth-aachen.de](mailto:post_acs@eonerc.rwth-aachen.de). + +# How to contribute +If you want to get more involved with DPsim, we welcome contributions of all kinds, including code, documentation, examples, models, bug reports, feature requests, and reviews. -## Contribute +Please open a Pull Request or issue on [GitHub](https://github.com/sogno-platform/dpsim), or start a discussion there to propose ideas and get feedback from the community. -If you want to get more involved by contributing to DPsim, please send us a Pull Request on [GitHub](https://github.com/sogno-platform/dpsim). +## Contributors +See [CONTRIBUTORS.md](https://github.com/sogno-platform/dpsim/blob/master/CONTRIBUTORS.md) for a list of contributors. -## Publications +# Publications If you are using DPsim for your research, please cite one of the following papers in your publications: diff --git a/docs/hugo/content/en/search.md b/docs/hugo/content/en/search.md index e3690fd5a8..db621987e5 100644 --- a/docs/hugo/content/en/search.md +++ b/docs/hugo/content/en/search.md @@ -3,4 +3,3 @@ title: Search Results layout: search --- - diff --git a/docs/hugo/docker-entrypoint.sh b/docs/hugo/docker-entrypoint.sh index 0e3a231af2..240fb43fb5 100755 --- a/docs/hugo/docker-entrypoint.sh +++ b/docs/hugo/docker-entrypoint.sh @@ -4,4 +4,4 @@ npm install -D --save autoprefixer npm install -D --save postcss-cli hugo --minify -hugo server --bind 0.0.0.0 -D \ No newline at end of file +hugo server --bind 0.0.0.0 -D diff --git a/docs/past-commits.txt b/docs/past-commits.txt index 0f7ff36085..da07a355ce 100644 --- a/docs/past-commits.txt +++ b/docs/past-commits.txt @@ -5321,4 +5321,3 @@ de4a03b811dae2d7441302a446c25b755680a022 search in standard location for Eigen Former-commit-id: c9310bac6e209da1b93386e119e21f011f92cc3c b3397eaff3d785202d6d1333400b66891454ca9b compile examples to avoid undefined references Former-commit-id: 095db5bbf729884810ff9d3b4cdb805557d92e04 - diff --git a/docs/sphinx/CMakeLists.txt b/docs/sphinx/CMakeLists.txt index 51c227708e..eeb5c10d0f 100644 --- a/docs/sphinx/CMakeLists.txt +++ b/docs/sphinx/CMakeLists.txt @@ -19,7 +19,7 @@ if(WITH_PYBIND) @ONLY ) - # We add the path of the freshly build dpsim.so module to Python path here + # We add the path of the freshly build dpsimpy extension to Python path here add_custom_target(docs COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_BINARY_DIR}:$ENV{PYTHONPATH} @@ -34,5 +34,9 @@ if(WITH_PYBIND) dpsimpy ) + install(DIRECTORY ${SPHINX_HTML_DIR} + DESTINATION ${CMAKE_INSTALL_DOCDIR}/sphinx + OPTIONAL + ) endif() endif() diff --git a/docs/sphinx/Reference.rst b/docs/sphinx/Reference.rst index b0d53f53dd..68ba21db04 100644 --- a/docs/sphinx/Reference.rst +++ b/docs/sphinx/Reference.rst @@ -50,4 +50,4 @@ Electromagnetic Transient Models .. automodule:: dpsimpy.sp.ph1 :members: - :undoc-members: \ No newline at end of file + :undoc-members: diff --git a/docs/sphinx/conf.py.in b/docs/sphinx/conf.py.in index 52c0e4ddcf..ee91abb4eb 100755 --- a/docs/sphinx/conf.py.in +++ b/docs/sphinx/conf.py.in @@ -20,38 +20,36 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ - 'sphinx.ext.autodoc' -] +extensions = ["sphinx.ext.autodoc"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'about' +master_doc = "about" # General information about the project. -project = '@PROJECT_NAME@' -copyright = '@PROJECT_COPYRIGHT@' -author = '@PROJECT_AUTHOR@' +project = "@PROJECT_NAME@" +copyright = "@PROJECT_COPYRIGHT@" +author = "@PROJECT_AUTHOR@" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '@DPSIM_VERSION@' +version = "@DPSIM_VERSION@" # The full version, including alpha/beta/rc tags. -release = '@DPSIM_VERSION@-@DPSIM_RELEASE@' +release = "@DPSIM_VERSION@-@DPSIM_RELEASE@" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -62,15 +60,15 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [ ] +html_static_path = [] -#html_logo = '@CMAKE_CURRENT_SOURCE_DIR@/images/dpsim.png' +# html_logo = '@CMAKE_CURRENT_SOURCE_DIR@/images/dpsim.png' html_context = { - 'source_url_prefix': "@PROJECT_VCS_URL@/docs/", -} \ No newline at end of file + "source_url_prefix": "@PROJECT_VCS_URL@/docs/", +} diff --git a/dpsim-models/CMakeLists.txt b/dpsim-models/CMakeLists.txt index 8f18461ec0..e51fd34162 100644 --- a/dpsim-models/CMakeLists.txt +++ b/dpsim-models/CMakeLists.txt @@ -16,3 +16,21 @@ set(MODELS_LIBRARIES ) add_subdirectory(src) + +file(GLOB_RECURSE HEADER_FILES include/*.h) + +target_sources(dpsim-models PUBLIC + FILE_SET public_headers + TYPE HEADERS + BASE_DIRS include + FILES "${HEADER_FILES}" +) + +install(TARGETS dpsim-models + EXPORT dpsim-models + FILE_SET public_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/dpsim-models/include/dpsim-models/Attribute.h b/dpsim-models/include/dpsim-models/Attribute.h index 2fafa6e0f4..14da779a9c 100644 --- a/dpsim-models/include/dpsim-models/Attribute.h +++ b/dpsim-models/include/dpsim-models/Attribute.h @@ -17,13 +17,13 @@ namespace CPS { /** - * Enum to describe when a given ´UpdateTask` should be executed. - * UPDATE_ONCE tasks are currently executed instantly after they have been set, and then never again. - * UPDATE_ON_GET tasks are executed whenever the attribute is dereferenced. - * UPDATE_ON_SET tasks are only executed whenever the `set` method is called. Since `get` provides mutable references, - * this is not guaranteed to happen on every change to the attribute! - * UPDATE_ON_SIMULATION_STEP is currently unused. - * */ + * Enum to describe when a given ´UpdateTask` should be executed. + * UPDATE_ONCE tasks are currently executed instantly after they have been set, and then never again. + * UPDATE_ON_GET tasks are executed whenever the attribute is dereferenced. + * UPDATE_ON_SET tasks are only executed whenever the `set` method is called. Since `get` provides mutable references, + * this is not guaranteed to happen on every change to the attribute! + * UPDATE_ON_SIMULATION_STEP is currently unused. + */ enum UpdateTaskKind { UPDATE_ONCE, UPDATE_ON_GET, @@ -38,11 +38,11 @@ template class AttributeStatic; template class AttributeDynamic; /** - * Custom pointer class for storing attributes as member variables and in the `mAttributes` attribute map. - * Using this type over the normal `std::shared_ptr` allows for disabling certain operator overloads, e.g. the comparison with the nullptr / the number 0 - * that is possible with shared ptrs. Since attribute pointers rarely need to be compared with the nullptr, disabling the implicit comparison allows for - * detecting more errors at compile time. Explicit comparison still remains possible via the `getPtr` method. - * */ + * Custom pointer class for storing attributes as member variables and in the `mAttributes` attribute map. + * Using this type over the normal `std::shared_ptr` allows for disabling certain operator overloads, e.g. the comparison with the nullptr / the number 0 + * that is possible with shared ptrs. Since attribute pointers rarely need to be compared with the nullptr, disabling the implicit comparison allows for + * detecting more errors at compile time. Explicit comparison still remains possible via the `getPtr` method. + */ template class AttributePointer { public: using element_type = T; @@ -90,37 +90,13 @@ template class AttributePointer { bool isNull() const { return mPtr == nullptr; } - /* - These (implicit) comparison operators are disabled to avoid accidentally comparing pointers instead of attribute values. - When a pointer comparison is necessary, this can be done via the `getPtr` method or by using the `AttributeCmp` and `AttributeEq` structs. - - template - bool operator<(const AttributePointer& rhs) const noexcept { - return this->mPtr < rhs.getPtr(); - } - - template - bool operator>(const AttributePointer& rhs) const noexcept { - return this->mPtr > rhs.getPtr(); - } - - template - bool operator==(const AttributePointer& rhs) const noexcept { - return this->mPtr == rhs.getPtr(); - } - - template - bool operator!=(const AttributePointer& rhs) const noexcept { - return this->mPtr != rhs.getPtr(); - }*/ - private: std::shared_ptr mPtr; }; /** - * Struct providing an (explicit) comparison function for Attribute Pointers. Can be used in STL containers. - * */ + * Struct providing an (explicit) comparison function for Attribute Pointers. Can be used in STL containers. + */ template struct AttributeCmp { bool operator()(CPS::AttributePointer a, CPS::AttributePointer b) const { @@ -129,8 +105,8 @@ template struct AttributeCmp { }; /** - * Struct providing an (explicit) equals function for Attribute Pointers. Can be used in STL containers. - * */ + * Struct providing an (explicit) equals function for Attribute Pointers. Can be used in STL containers. + */ template struct AttributeEq { bool operator()(CPS::AttributePointer a, CPS::AttributePointer b) const { @@ -139,8 +115,8 @@ template struct AttributeEq { }; /** - * Base class for all Attribute types. Can be used in STL containers to hide the template information. - * */ + * Base class for all Attribute types. Can be used in STL containers to hide the template information. + */ class AttributeBase { public: typedef AttributePointer Ptr; @@ -149,47 +125,47 @@ class AttributeBase { typedef std::map Map; /** - * Display this attribute's value as a string - * */ + * Display this attribute's value as a string + */ virtual String toString() = 0; /** - * Check whether this is a static or dynamic attribute - * @return true for instances of `AttributeStatic`, false for instances of `AttributeDynamic` - * */ + * Check whether this is a static or dynamic attribute + * @return true for instances of `AttributeStatic`, false for instances of `AttributeDynamic` + */ virtual bool isStatic() const = 0; virtual ~AttributeBase() = default; /** - * @brief Copy the attribute value of `copyFrom` onto this attribute - * @return true if the copy operation was successful, false otherwise - */ + * @brief Copy the attribute value of `copyFrom` onto this attribute + * @return true if the copy operation was successful, false otherwise + */ virtual bool copyValue(AttributeBase::Ptr copyFrom) = 0; /** - * @brief Get the type of this attribute - * @return std::type_info - */ + * @brief Get the type of this attribute + * @return std::type_info + */ virtual const std::type_info &getType() = 0; /** - * @brief Generates a new attribute of the same type and copies the current value in the heap. Does not copy any dependency relations! - * @return Pointer to the copied attribute - */ + * @brief Generates a new attribute of the same type and copies the current value in the heap. Does not copy any dependency relations! + * @return Pointer to the copied attribute + */ virtual AttributeBase::Ptr cloneValueOntoNewAttribute() = 0; /** - * Append all dependencies of this attribute to the given set. - * For static attributes, this will only append `this`, for dynamic attributes, it will recursively collect and append - * all dependencies. - * */ + * Append all dependencies of this attribute to the given set. + * For static attributes, this will only append `this`, for dynamic attributes, it will recursively collect and append + * all dependencies. + */ virtual void appendDependencies(AttributeBase::Set *deps) = 0; /** - * Get a set of all attributes this attribute depends on. For static attributes, this set will only contain `this`. - * For dynamic attributes, this will recursively collect all dependency attributes. - * */ + * Get a set of all attributes this attribute depends on. For static attributes, this set will only contain `this`. + * For dynamic attributes, this will recursively collect all dependency attributes. + */ virtual AttributeBase::Set getDependencies() final { AttributeBase::Set deps = AttributeBase::Set(); this->appendDependencies(&deps); @@ -198,8 +174,8 @@ class AttributeBase { }; /** - * Base class for all AttributeUpdateTasks. Enables storing tasks in an STL list independent of the dependency types. - * */ + * Base class for all AttributeUpdateTasks. Enables storing tasks in an STL list independent of the dependency types. + */ template class AttributeUpdateTaskBase { public: @@ -211,10 +187,10 @@ template class AttributeUpdateTaskBase { }; /** - * Specialized class for AttributeUpdateTasks that includes information about the types of attributes this task depends on. - * @param DependentType The type of the attribute which is updated by this task - * @param DependencyTypes List of the types of the attributes whose values are used to update the dependent attribute - * */ + * Specialized class for AttributeUpdateTasks that includes information about the types of attributes this task depends on. + * @param DependentType The type of the attribute which is updated by this task + * @param DependencyTypes List of the types of the attributes whose values are used to update the dependent attribute + */ template class AttributeUpdateTask : public AttributeUpdateTaskBase, @@ -246,8 +222,8 @@ class AttributeUpdateTask } /** - * Returns all dependency elements in the `mDependency` tuple in a list over AttributeBase pointers. - * */ + * Returns all dependency elements in the `mDependency` tuple in a list over AttributeBase pointers. + */ virtual AttributeBase::List getDependencies() override { return std::apply( [](auto &&...elems) { @@ -259,9 +235,9 @@ class AttributeUpdateTask }; /** - * Main Attribute class. The template class `T` holds the attribute's type. This is used as the type for all attribute member variables. - * @param T The type of this attribute - * */ + * Main Attribute class. The template class `T` holds the attribute's type. This is used as the type for all attribute member variables. + * @param T The type of this attribute + */ template class Attribute : public AttributeBase, public std::enable_shared_from_this> { @@ -279,57 +255,62 @@ class Attribute : public AttributeBase, } /** - * Manually set the attribute to the given value. For dynamic attributes, this will trigger the UPDATE_ON_SET tasks for updating any - * dependency attributes. - * */ + * Manually set the attribute to the given value. For dynamic attributes, this will trigger the UPDATE_ON_SET tasks for updating any + * dependency attributes. + */ virtual void set(T value) = 0; /** - * Get a mutable reference to the attribute's underlying data. This method is also called when dereferencing an attribute using the * operator - * */ + * Get a mutable reference to the attribute's underlying data. This method is also called when dereferencing an attribute using the * operator + */ virtual T &get() = 0; /** - * Convenience method for setting this attribute to always equal another attribute. - * When `this` is dynamic, this will set up an UPDATE_ONCE task that sets this attribute's data pointer to equal the data pointer of the referenced attribute. - * If `this` is static, calling this method will result in a runtime error. - * @param reference The attribute which's value will be adapted - * */ + * Convenience method for setting this attribute to always equal another attribute. + * When `this` is dynamic, this will set up an UPDATE_ONCE task that sets this attribute's data pointer to equal the data pointer of the referenced attribute. + * If `this` is static, calling this method will result in a runtime error. + * @param reference The attribute which's value will be adapted + */ virtual void setReference(Attribute::Ptr reference) = 0; /** - * Exposing the underlying shared_ptr for this attribute's data. Used to create reference relations between two attributes. - * @return The shared_ptr to this attribute's underlying data - * */ + * Exposing the underlying shared_ptr for this attribute's data. Used to create reference relations between two attributes. + * @return The shared_ptr to this attribute's underlying data + */ virtual std::shared_ptr asRawPointer() = 0; - /// Fallback method for all attribute types not covered by the specifications in Attribute.cpp + /** + * @brief Fallback method for all attribute types not covered by the specifications in Attribute.cpp + */ String toString() override { std::stringstream ss; ss << this->get(); return ss.str(); } - /// @brief User-defined cast operator - /// - /// Allows attributes to be casted to their value type: - /// - /// Real v = 1.2; - /// auto a = Attribute(&v); - /// - /// Real x = v; - /// + /** + * @brief User-defined cast operator + * + * Allows attributes to be casted to their value type: + * + * Real v = 1.2; + * auto a = Attribute(&v); + * + * Real x = v; + */ operator const T &() { return this->get(); } - /// @brief User-defined dereference operator - /// - /// Allows easier access to the attribute's underlying data + /** + * @brief User-defined dereference operator + * + * Allows easier access to the attribute's underlying data + */ T &operator*() { return this->get(); } /** - * @brief Copy the attribute value of `copyFrom` onto this attribute - * @return true if the copy operation was successful, false otherwise - */ + * @brief Copy the attribute value of `copyFrom` onto this attribute + * @return true if the copy operation was successful, false otherwise + */ bool copyValue(AttributeBase::Ptr copyFrom) override { Attribute::Ptr copyFromTyped = std::dynamic_pointer_cast>(copyFrom.getPtr()); @@ -341,15 +322,15 @@ class Attribute : public AttributeBase, } /** - * @brief Get the type of this attribute - * @return std::type_info - */ + * @brief Get the type of this attribute + * @return std::type_info + */ const std::type_info &getType() override { return typeid(T); } /** - * @brief Generates a new attribute of the same type and copies the current value in the heap. Does not copy any dependency relations! - * @return Pointer to the copied attribute - */ + * @brief Generates a new attribute of the same type and copies the current value in the heap. Does not copy any dependency relations! + * @return Pointer to the copied attribute + */ AttributeBase::Ptr cloneValueOntoNewAttribute() override { return AttributePointer( AttributeStatic::make(this->get())); @@ -357,13 +338,13 @@ class Attribute : public AttributeBase, }; /** - * General method for deriving a new attribute from this attribute. Custom getter and setter functions have to be provided. The newly created - * attribute will only depend on this attribute in a 1:1 relationship. - * @param U The type of the newly derived attribute - * @param getter The getter actor function to use for updating the derived attribute - * @param setter The setter actor function for updating `this` when the derived attribute is changed - * @return a newly created attribute of type `U` which will calculate its value using the provided getter and update `this` on changes using the provided setter - * */ + * General method for deriving a new attribute from this attribute. Custom getter and setter functions have to be provided. The newly created + * attribute will only depend on this attribute in a 1:1 relationship. + * @param U The type of the newly derived attribute + * @param getter The getter actor function to use for updating the derived attribute + * @param setter The setter actor function for updating `this` when the derived attribute is changed + * @return a newly created attribute of type `U` which will calculate its value using the provided getter and update `this` on changes using the provided setter + */ template typename Attribute::Ptr derive(typename AttributeUpdateTask::Actor getter = @@ -389,9 +370,9 @@ class Attribute : public AttributeBase, } /** - * Convenience method for deriving the real part of a complex attribute - * @return a new attribute whose value will always equal the real part of `this` - * */ + * Convenience method for deriving the real part of a complex attribute + * @return a new attribute whose value will always equal the real part of `this` + */ template , bool> = true> AttributePointer> deriveReal() @@ -413,9 +394,9 @@ class Attribute : public AttributeBase, } /** - * Convenience method for deriving the imaginary part of a complex attribute - * @return a new attribute whose value will always equal the imaginary part of `this` - * */ + * Convenience method for deriving the imaginary part of a complex attribute + * @return a new attribute whose value will always equal the imaginary part of `this` + */ template , bool> = true> AttributePointer> deriveImag() @@ -437,9 +418,9 @@ class Attribute : public AttributeBase, } /** - * Convenience method for deriving the magnitude of a complex attribute - * @return a new attribute whose value will always equal the magnitude of `this` - * */ + * Convenience method for deriving the magnitude of a complex attribute + * @return a new attribute whose value will always equal the magnitude of `this` + */ template , bool> = true> AttributePointer> deriveMag() @@ -460,9 +441,9 @@ class Attribute : public AttributeBase, } /** - * Convenience method for deriving the phase of a complex attribute - * @return a new attribute whose value will always equal the phase of `this` - * */ + * Convenience method for deriving the phase of a complex attribute + * @return a new attribute whose value will always equal the phase of `this` + */ template , bool> = true> AttributePointer> derivePhase() @@ -483,10 +464,10 @@ class Attribute : public AttributeBase, } /** - * Convenience method for deriving an attribute whose value is always scaled by `scale` - * @param scale The scaling to apply to the attribute's value - * @return a new attribute whose value will always equal the value of `this` but scaled by `scale` - * */ + * Convenience method for deriving an attribute whose value is always scaled by `scale` + * @param scale The scaling to apply to the attribute's value + * @return a new attribute whose value will always equal the value of `this` but scaled by `scale` + */ template || std::is_same_v, bool> = true> @@ -505,12 +486,12 @@ class Attribute : public AttributeBase, } /** - * Convenience method for deriving an attribute which covers one coefficient of this matrix - * @param U The type of the coefficient (usally Real or Complex) - * @param row The coefficients row coordinate - * @param column The coefficients column coordinate - * @return a new attribute whose value will always equal the value of the coefficient `this(row, column)` - * */ + * Convenience method for deriving an attribute which covers one coefficient of this matrix + * @param U The type of the coefficient (usally Real or Complex) + * @param row The coefficients row coordinate + * @param column The coefficients column coordinate + * @return a new attribute whose value will always equal the value of the coefficient `this(row, column)` + */ template , V>, bool> = true> AttributePointer> @@ -535,9 +516,9 @@ class Attribute : public AttributeBase, }; /** - * Class for static attributes. A static attribute's value can only ever by changed via the `get` and `set` methods (or the reference provided by `get`). - * Static attributes do not directly depend on any other attributes and currently cannot have any update tasks. - * */ + * Class for static attributes. A static attribute's value can only ever by changed via the `get` and `set` methods (or the reference provided by `get`). + * Static attributes do not directly depend on any other attributes and currently cannot have any update tasks. + */ template class AttributeStatic : public Attribute, public SharedFactory> { @@ -564,8 +545,8 @@ class AttributeStatic : public Attribute, }; /** - * Class for dynamic attributes. A dynamic attribute has an internal value which can be updated by update tasks. - * */ + * Class for dynamic attributes. A dynamic attribute has an internal value which can be updated by update tasks. + */ template class AttributeDynamic : public Attribute, public SharedFactory> { @@ -580,16 +561,16 @@ class AttributeDynamic : public Attribute, AttributeDynamic(T initialValue = T()) : Attribute(initialValue) {} /** - * Allows for adding a new update task to this attribute. - * @param kind The kind of update task - * @param task The update task itself - * */ + * Allows for adding a new update task to this attribute. + * @param kind The kind of update task + * @param task The update task itself + */ void addTask(UpdateTaskKind kind, typename AttributeUpdateTaskBase::Ptr task) { switch (kind) { case UpdateTaskKind::UPDATE_ONCE: updateTasksOnce.push_back(task); - ///THISISBAD: This is probably not the right time to run this kind of task + // THISISBAD: This is probably not the right time to run this kind of task task->executeUpdate(this->mData); break; case UpdateTaskKind::UPDATE_ON_GET: @@ -604,9 +585,9 @@ class AttributeDynamic : public Attribute, } /** - * Removes all update tasks of a given kind from this attribute. - * @param kind The kind of tasks to remove - * */ + * Removes all update tasks of a given kind from this attribute. + * @param kind The kind of tasks to remove + */ void clearTasks(UpdateTaskKind kind) { switch (kind) { case UpdateTaskKind::UPDATE_ONCE: @@ -624,8 +605,8 @@ class AttributeDynamic : public Attribute, } /** - * Remove all update tasks from this attribute, regardless of their kind. - * */ + * Remove all update tasks from this attribute, regardless of their kind. + */ void clearAllTasks() { updateTasksOnce.clear(); updateTasksOnGet.clear(); @@ -674,10 +655,10 @@ class AttributeDynamic : public Attribute, virtual bool isStatic() const override { return false; } /** - * Implementation for dynamic attributes.This will recursively collect all attributes this attribute depends on, either in the UPDATE_ONCE or the UPDATE_ON_GET tasks. - * This is done by performing a Depth-First-Search on the dependency graph where the task dependencies of each attribute are the outgoing edges. - * The `deps` set contains all the nodes that have already been visited in the graph - * */ + * Implementation for dynamic attributes.This will recursively collect all attributes this attribute depends on, either in the UPDATE_ONCE or the UPDATE_ON_GET tasks. + * This is done by performing a Depth-First-Search on the dependency graph where the task dependencies of each attribute are the outgoing edges. + * The `deps` set contains all the nodes that have already been visited in the graph + */ virtual void appendDependencies(AttributeBase::Set *deps) override { deps->insert(this->shared_from_this()); @@ -708,8 +689,8 @@ template <> String Attribute::toString(); namespace std { /** - * Struct for making the custom `AttributePointer` type hashable. This enables these pointers to be used in STL Maps. - * */ + * Struct for making the custom `AttributePointer` type hashable. This enables these pointers to be used in STL Maps. + */ template struct hash> { size_t operator()(CPS::AttributePointer const &x) const { return std::hash>()(x.getPtr()); diff --git a/dpsim-models/include/dpsim-models/AttributeList.h b/dpsim-models/include/dpsim-models/AttributeList.h index eab0aaeba4..af90d68b42 100644 --- a/dpsim-models/include/dpsim-models/AttributeList.h +++ b/dpsim-models/include/dpsim-models/AttributeList.h @@ -29,9 +29,7 @@ class AttributeList : public SharedFactory { const AttributeBase::Map &attributes() const { return mAttributeMap; }; - /** - * Creates a new static Attribute and enters a pointer to it into this Attribute Map using the provided name. - * */ + // Creates a new static Attribute and enters a pointer to it into this Attribute Map using the provided name. template typename Attribute::Ptr create(const String &name, T intitialValue = T()) { typename Attribute::Ptr newAttr = @@ -40,9 +38,7 @@ class AttributeList : public SharedFactory { return newAttr; } - /** - * Creates a new dynamic Attribute and enters a pointer to it into this Attribute Map using the provided name. - * */ + // Creates a new dynamic Attribute and enters a pointer to it into this Attribute Map using the provided name. template typename Attribute::Ptr createDynamic(const String &name) { typename Attribute::Ptr newAttr = diff --git a/dpsim-models/include/dpsim-models/Base/Base_Ph1_Switch.h b/dpsim-models/include/dpsim-models/Base/Base_Ph1_Switch.h index 0ec6fe0fa5..732e30d32d 100644 --- a/dpsim-models/include/dpsim-models/Base/Base_Ph1_Switch.h +++ b/dpsim-models/include/dpsim-models/Base/Base_Ph1_Switch.h @@ -16,6 +16,9 @@ namespace Base { namespace Ph1 { /// Dynamic Phasor Three-Phase Switch class Switch { +protected: + Bool mIsClosedPrev = false; + public: /// Resistance if switch is open [ohm] const Attribute::Ptr mOpenResistance; diff --git a/dpsim-models/include/dpsim-models/Base/Base_Ph1_Transformer.h b/dpsim-models/include/dpsim-models/Base/Base_Ph1_Transformer.h index acd208c52d..742deaf58b 100644 --- a/dpsim-models/include/dpsim-models/Base/Base_Ph1_Transformer.h +++ b/dpsim-models/include/dpsim-models/Base/Base_Ph1_Transformer.h @@ -15,11 +15,13 @@ namespace CPS { namespace Base { namespace Ph1 { class Transformer { -public: +protected: /// Nominal voltage of primary side - const Attribute::Ptr mNominalVoltageEnd1; + Real mNominalVoltageEnd1; /// Nominal voltage of secondary side - const Attribute::Ptr mNominalVoltageEnd2; + Real mNominalVoltageEnd2; + +public: /// Rated Apparent Power [VA] const Attribute::Ptr mRatedPower; /// Complex transformer ratio @@ -30,11 +32,7 @@ class Transformer { const Attribute::Ptr mInductance; explicit Transformer(CPS::AttributeList::Ptr attributeList) - : mNominalVoltageEnd1( - attributeList->create("nominal_voltage_end1")), - mNominalVoltageEnd2( - attributeList->create("nominal_voltage_end2")), - mRatedPower(attributeList->create("S")), + : mRatedPower(attributeList->create("S")), mRatio(attributeList->create("ratio")), mResistance(attributeList->create("R")), mInductance(attributeList->create("L")){}; @@ -42,8 +40,8 @@ class Transformer { /// void setParameters(Real nomVoltageEnd1, Real nomVoltageEnd2, Real ratioAbs, Real ratioPhase, Real resistance, Real inductance) { - **mNominalVoltageEnd1 = nomVoltageEnd1; - **mNominalVoltageEnd2 = nomVoltageEnd2; + mNominalVoltageEnd1 = nomVoltageEnd1; + mNominalVoltageEnd2 = nomVoltageEnd2; **mRatio = std::polar(ratioAbs, ratioPhase); **mResistance = resistance; **mInductance = inductance; diff --git a/dpsim-models/include/dpsim-models/Base/Base_Ph3_Switch.h b/dpsim-models/include/dpsim-models/Base/Base_Ph3_Switch.h index 02b7f2f49b..f8280df21f 100644 --- a/dpsim-models/include/dpsim-models/Base/Base_Ph3_Switch.h +++ b/dpsim-models/include/dpsim-models/Base/Base_Ph3_Switch.h @@ -15,28 +15,34 @@ namespace Base { namespace Ph3 { /// Dynamic Phasor Three-Phase Switch class Switch { +protected: + Bool mIsClosedPrev = false; + public: /// Resistance if switch is open [ohm] const CPS::Attribute::Ptr mOpenResistance; /// Resistance if switch is closed [ohm] const CPS::Attribute::Ptr mClosedResistance; /// Defines if Switch is open or closed - const CPS::Attribute::Ptr mSwitchClosed; + const CPS::Attribute::Ptr mIsClosed; explicit Switch(CPS::AttributeList::Ptr attributeList) : mOpenResistance(attributeList->create("R_open")), mClosedResistance(attributeList->create("R_closed")), - mSwitchClosed(attributeList->create("is_closed")){}; + mIsClosed(attributeList->create("is_closed")){}; /// void setParameters(Matrix openResistance, Matrix closedResistance, Bool closed = false) { **mOpenResistance = openResistance; **mClosedResistance = closedResistance; - **mSwitchClosed = closed; + **mIsClosed = closed; } - void closeSwitch() { **mSwitchClosed = true; } - void openSwitch() { **mSwitchClosed = false; } + void closeSwitch() { **mIsClosed = true; } + void openSwitch() { **mIsClosed = false; } + + /// Check if switch is closed + Bool isClosed() { return **mIsClosed; } }; } // namespace Ph3 } // namespace Base diff --git a/dpsim-models/include/dpsim-models/CIM/Reader.h b/dpsim-models/include/dpsim-models/CIM/Reader.h index 71f6032ea1..262b6cf034 100644 --- a/dpsim-models/include/dpsim-models/CIM/Reader.h +++ b/dpsim-models/include/dpsim-models/CIM/Reader.h @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -47,6 +49,8 @@ class PowerTransformer; class EquivalentShunt; class TopologicalNode; class ConductingEquipment; +class Disconnector; +class Breaker; }; // namespace CIMPP #else #include @@ -54,6 +58,22 @@ class ConductingEquipment; namespace CPS { namespace CIM { +template +struct has_value_member : std::false_type {}; + +template +struct has_value_member().value)>> + : std::true_type {}; + +template const auto &cimString(const T &field) { + if constexpr (has_value_member::value) { + return field.value; + } else { + return field; + } +} + class InvalidTopology {}; class Reader { @@ -146,6 +166,8 @@ class Reader { mapExternalNetworkInjection(CIMPP::ExternalNetworkInjection *extnet); /// Returns a shunt TopologicalPowerComp::Ptr mapEquivalentShunt(CIMPP::EquivalentShunt *shunt); + TopologicalPowerComp::Ptr mapDisconnector(CIMPP::Disconnector *disc); + TopologicalPowerComp::Ptr mapBreaker(CIMPP::Breaker *cb); // #### Helper Functions #### /// Determine base voltage associated with object diff --git a/dpsim-models/include/dpsim-models/CSVReader.h b/dpsim-models/include/dpsim-models/CSVReader.h index 2ec921122b..06d255d8f5 100644 --- a/dpsim-models/include/dpsim-models/CSVReader.h +++ b/dpsim-models/include/dpsim-models/CSVReader.h @@ -43,12 +43,12 @@ class CSVReader { /// MANUAL for providing an assign pattern manually. see power flow example: CIM/CIGRE_MV_PowerFlowTest_LoadProfiles.cpp enum class Mode { AUTO, MANUAL }; - /* - Time Stamp Format. - HHMMSS: Hours : Minutes : Seconds, it be casted to the corresponding SECONDS. - SECONDS: profiles recorded with total seconds. - PVGEN: format comply with https://www.fein-aachen.org/projects/PVgenerator/ - */ + /* Time Stamp Format. + * + * HHMMSS: Hours : Minutes : Seconds, it be casted to the corresponding SECONDS. + * SECONDS: profiles recorded with total seconds. + * PVGEN: format comply with https://www.fein-aachen.org/projects/PVgenerator/ + */ enum class DataFormat { HHMMSS, SECONDS, HOURS, MINUTES }; /// @@ -62,8 +62,8 @@ class CSVReader { CSVReader(String name, String path, std::map &assignList, Logger::Level logLevel); - /// convert HH:MM:SS format timestamp into total seconds. - /// e.g.: 00 : 01 : 00 -- > 60. + /// Convert HH:MM:SS format timestamp into total seconds. + /// e.g.: 00 : 01 : 00 -- > 60. Real time_format_convert(const String &time); /// Skip first row if it has no digits at beginning void doSkipFirstRow(Bool value = true) { mSkipFirstRow = value; } @@ -75,16 +75,6 @@ class CSVReader { Real end_time = -1, Real scale_factor = 1, CSVReader::DataFormat format = CSVReader::DataFormat::SECONDS); - // void assignLoadProfilePF(std::vector>& loads, - // Real start_time = -1, Real time_step = 1, Real end_time = -1, Real scale_factor= 1, - // CSVReader::Mode mode = CSVReader::Mode::AUTO, - // CSVReader::DataFormat format = CSVReader::DataFormat::SECONDS); - - // void assignLoadProfileSP(std::vector>& loads, - // Real start_time = -1, Real time_step = 1, Real end_time = -1, Real scale_factor= 1, - // CSVReader::Mode mode = CSVReader::Mode::AUTO, - // CSVReader::DataFormat format = CSVReader::DataFormat::SECONDS); - void assignLoadProfileDP( std::vector> &loads, diff --git a/dpsim-models/include/dpsim-models/Components.h b/dpsim-models/include/dpsim-models/Components.h index 0c53e76fc9..b30ee1a7d4 100644 --- a/dpsim-models/include/dpsim-models/Components.h +++ b/dpsim-models/include/dpsim-models/Components.h @@ -51,6 +51,9 @@ #include #include #include +#ifdef WITH_VILLAS +#include +#endif #include #include #include @@ -72,6 +75,7 @@ #include #include +#include #include #include #include @@ -83,15 +87,20 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include #include -#include #include #include #include +#include #include #include #include @@ -128,6 +137,7 @@ #include #include #include +#include #include #include #include diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph1_PiLine.h b/dpsim-models/include/dpsim-models/DP/DP_Ph1_PiLine.h index ab6e0cbb57..bf35582e6f 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph1_PiLine.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph1_PiLine.h @@ -1,10 +1,7 @@ -/* Copyright 2017-2021 Institute for Automation of Complex Power Systems, - * EONERC, RWTH Aachen University - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - *********************************************************************************/ +/* Author: Christoph Wirtz + * SPDX-FileCopyrightText: 2025 FGH e.V. + * SPDX-License-Identifier: MPL-2.0 + */ #pragma once diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph1_ProfileVoltageSource.h b/dpsim-models/include/dpsim-models/DP/DP_Ph1_ProfileVoltageSource.h index a058929fa3..6fd09d6e13 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph1_ProfileVoltageSource.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph1_ProfileVoltageSource.h @@ -22,7 +22,9 @@ namespace CPS { namespace DP { namespace Ph1 { -class ProfileVoltageSource : public MNASimPowerComp, public DAEInterface, public SharedFactory { +class ProfileVoltageSource : public MNASimPowerComp, + public DAEInterface, + public SharedFactory { private: /// void updateVoltage(Real time); @@ -38,9 +40,13 @@ class ProfileVoltageSource : public MNASimPowerComp, public DAEInterfac const CPS::Attribute::Ptr mVoltage; /// Defines UID, name, component parameters and logging level - ProfileVoltageSource(String uid, String name, std::filesystem::path sourceFile, Logger::Level loglevel = Logger::Level::off); + ProfileVoltageSource(String uid, String name, + std::filesystem::path sourceFile, + Logger::Level loglevel = Logger::Level::off); /// Defines UID, name, component parameters and logging level - ProfileVoltageSource(String name, std::filesystem::path sourceFile, Logger::Level logLevel = Logger::Level::off) : ProfileVoltageSource(name, name, sourceFile, logLevel) {} + ProfileVoltageSource(String name, std::filesystem::path sourceFile, + Logger::Level logLevel = Logger::Level::off) + : ProfileVoltageSource(name, name, sourceFile, logLevel) {} /// SimPowerComp::Ptr clone(String name) override; @@ -52,11 +58,15 @@ class ProfileVoltageSource : public MNASimPowerComp, public DAEInterfac // #### MNA Section #### /// Initializes internal variables of the component - void mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) override; - void mnaCompInitializeHarm(Real omega, Real timeStep, std::vector::Ptr> leftVectors) override; + void mnaCompInitialize(Real omega, Real timeStep, + Attribute::Ptr leftVector) override; + void mnaCompInitializeHarm( + Real omega, Real timeStep, + std::vector::Ptr> leftVectors) override; /// Stamps system matrix void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override; - void mnaCompApplySystemMatrixStampHarm(SparseMatrixRow &systemMatrix, Int freqIdx) override; + void mnaCompApplySystemMatrixStampHarm(SparseMatrixRow &systemMatrix, + Int freqIdx) override; /// Stamps right side (source) vector void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override; void mnaCompApplyRightSideVectorStampHarm(Matrix &rightVector) override; @@ -65,16 +75,25 @@ class ProfileVoltageSource : public MNASimPowerComp, public DAEInterfac /// MNA pre step operations void mnaCompPreStep(Real time, Int timeStepCount) override; /// MNA post step operations - void mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) override; + void mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; /// Add MNA pre step dependencies - void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override; + void mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; /// Add MNA post step dependencies - void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector) override; + void + mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; class MnaPreStepHarm : public CPS::Task { public: - MnaPreStepHarm(ProfileVoltageSource &voltageSource) : Task(**voltageSource.mName + ".MnaPreStepHarm"), mVoltageSource(voltageSource) { + MnaPreStepHarm(ProfileVoltageSource &voltageSource) + : Task(**voltageSource.mName + ".MnaPreStepHarm"), + mVoltageSource(voltageSource) { mAttributeDependencies.push_back(mVoltageSource.mVoltage); mModifiedAttributes.push_back(mVoltageSource.mRightVector); mModifiedAttributes.push_back(mVoltageSource.mIntfVoltage); @@ -87,8 +106,10 @@ class ProfileVoltageSource : public MNASimPowerComp, public DAEInterfac class MnaPostStepHarm : public CPS::Task { public: - MnaPostStepHarm(ProfileVoltageSource &voltageSource, const std::vector::Ptr> &leftVectors) - : Task(**voltageSource.mName + ".MnaPostStepHarm"), mVoltageSource(voltageSource), mLeftVectors(leftVectors) { + MnaPostStepHarm(ProfileVoltageSource &voltageSource, + const std::vector::Ptr> &leftVectors) + : Task(**voltageSource.mName + ".MnaPostStepHarm"), + mVoltageSource(voltageSource), mLeftVectors(leftVectors) { for (UInt i = 0; i < mLeftVectors.size(); i++) mAttributeDependencies.push_back(mLeftVectors[i]); mModifiedAttributes.push_back(mVoltageSource.mIntfCurrent); @@ -102,7 +123,8 @@ class ProfileVoltageSource : public MNASimPowerComp, public DAEInterfac // #### DAE Section #### /// Residual function for DAE Solver - void daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector &off) override; + void daeResidual(double ttime, const double state[], const double dstate_dt[], + double resid[], std::vector &off) override; /// Voltage Getter Complex daeInitialize() override; }; diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph1_RXLoadSwitch.h b/dpsim-models/include/dpsim-models/DP/DP_Ph1_RXLoadSwitch.h index 4663d01e21..d59ddc3897 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph1_RXLoadSwitch.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph1_RXLoadSwitch.h @@ -17,6 +17,7 @@ namespace Ph1 { /// Constant impedance load model consisting of RLC elements class RXLoadSwitch : public CompositePowerComp, public MNASwitchInterface, + public MNAVariableCompInterface, public SharedFactory { protected: /// Internal RXLoad @@ -73,6 +74,9 @@ class RXLoadSwitch : public CompositePowerComp, void mnaCompApplySwitchSystemMatrixStamp(Bool closed, SparseMatrixRow &systemMatrix, Int freqIdx) override; + + // #### MNA section for variable component #### + Bool hasParameterChanged() override; }; } // namespace Ph1 } // namespace DP diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph1_Switch.h b/dpsim-models/include/dpsim-models/DP/DP_Ph1_Switch.h index 268d8798d4..05c2ecb77e 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph1_Switch.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph1_Switch.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include namespace CPS { namespace DP { @@ -25,8 +25,8 @@ namespace Ph1 { class Switch : public MNASimPowerComp, public Base::Ph1::Switch, public SharedFactory, - public MNASwitchInterface { -protected: + public MNASwitchInterface, + public MNAVariableCompInterface { public: /// Defines UID, name, component parameters and logging level Switch(String uid, String name, Logger::Level loglevel = Logger::Level::off); @@ -68,6 +68,9 @@ class Switch : public MNASimPowerComp, void mnaCompApplySwitchSystemMatrixStamp(Bool closed, SparseMatrixRow &systemMatrix, Int freqIdx); + + // #### MNA section for variable component #### + Bool hasParameterChanged(); }; } // namespace Ph1 } // namespace DP diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph1_varResSwitch.h b/dpsim-models/include/dpsim-models/DP/DP_Ph1_varResSwitch.h index 2efaf53238..5f4d35ce44 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph1_varResSwitch.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph1_varResSwitch.h @@ -31,7 +31,6 @@ class varResSwitch : public MNASimPowerComp, public SharedFactory { protected: - Bool mPrevState = false; Real mDeltaResClosed = 0; Real mDeltaResOpen = 1.5; Real mPrevRes; // previous resistance value to multiply with rate of change @@ -94,6 +93,7 @@ class varResSwitch : public MNASimPowerComp, SparseMatrixRow &systemMatrix, Int freqIdx); + // #### MNA section for variable component #### Bool hasParameterChanged(); }; } // namespace Ph1 diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph3_Inductor.h b/dpsim-models/include/dpsim-models/DP/DP_Ph3_Inductor.h index 3634e722df..571ac07a77 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph3_Inductor.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph3_Inductor.h @@ -79,11 +79,11 @@ class Inductor : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; - + // #### MNA Tear Section #### void mnaTearInitialize(Real omega, Real timestep) override; void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; void mnaTearApplyVoltageStamp(Matrix &voltageVector) override; - void mnaTearPostStep(Complex voltage, Complex current) override; + void mnaTearPostStep(MatrixComp voltage, MatrixComp current) override; }; } // namespace Ph3 } // namespace DP diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph3_PiLine.h b/dpsim-models/include/dpsim-models/DP/DP_Ph3_PiLine.h new file mode 100644 index 0000000000..d36d42c93b --- /dev/null +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph3_PiLine.h @@ -0,0 +1,83 @@ +/* Author: Christoph Wirtz + * SPDX-FileCopyrightText: 2025 FGH e.V. + * SPDX-License-Identifier: MPL-2.0 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace CPS { +namespace DP { +namespace Ph3 { +/// \brief PI-line dynamic phasor model +/// +/// This model consists sub components to represent the +/// RLC elements of a PI-line. +class PiLine : public CompositePowerComp, + public MNATearInterface, + public Base::Ph3::PiLine, + public SharedFactory { +protected: + /// Series Inductance submodel + std::shared_ptr mSubSeriesInductor; + /// Series Resistor submodel + std::shared_ptr mSubSeriesResistor; + /// Parallel Resistor submodel at Terminal 0 + std::shared_ptr mSubParallelResistor0; + // Parallel Capacitor submodel at Terminal 0 + std::shared_ptr mSubParallelCapacitor0; + /// Parallel resistor submodel at Terminal 1 + std::shared_ptr mSubParallelResistor1; + /// Parallel capacitor submodel at Terminal 1 + std::shared_ptr mSubParallelCapacitor1; + /// Right side vectors of subcomponents + std::vector mRightVectorStamps; + +public: + /// Defines UID, name and logging level + PiLine(String uid, String name, Logger::Level logLevel = Logger::Level::off); + /// Defines name and logging level + PiLine(String name, Logger::Level logLevel = Logger::Level::off) + : PiLine(name, name, logLevel) {} + + SimPowerComp::Ptr clone(String copySuffix) override; + + // #### General #### + /// Initializes component from power flow data + void initializeFromNodesAndTerminals(Real frequency) override; + + // #### MNA section #### + /// Updates internal current variable of the component + void mnaCompUpdateCurrent(const Matrix &leftVector) override; + /// Updates internal voltage variable of the component + void mnaCompUpdateVoltage(const Matrix &leftVector) override; + /// MNA pre and post step operations + void mnaParentPreStep(Real time, Int timeStepCount) override; + void mnaParentPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; + /// add MNA pre and post step dependencies + void mnaParentAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; + void + mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; + + MNAInterface::List mnaTearGroundComponents() override; + void mnaTearInitialize(Real omega, Real timeStep) override; + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; + void mnaTearApplyVoltageStamp(Matrix &voltageVector) override; + void mnaTearPostStep(MatrixComp voltage, MatrixComp current) override; +}; +} // namespace Ph3 +} // namespace DP +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph3_Resistor.h b/dpsim-models/include/dpsim-models/DP/DP_Ph3_Resistor.h index bd7479e75b..496a11144d 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph3_Resistor.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph3_Resistor.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include namespace CPS { namespace DP { @@ -20,6 +20,7 @@ namespace Ph3 { /// class Resistor : public MNASimPowerComp, public Base::Ph3::Resistor, + public MNATearInterface, public SharedFactory { public: @@ -54,6 +55,9 @@ class Resistor : public MNASimPowerComp, Attribute::Ptr &leftVector) override; void mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) override; + + // #### MNA Tear Section #### + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; }; } // namespace Ph3 } // namespace DP diff --git a/dpsim-models/include/dpsim-models/DP/DP_Ph3_SeriesSwitch.h b/dpsim-models/include/dpsim-models/DP/DP_Ph3_SeriesSwitch.h index 7bdbe2b30b..4c390ca76e 100644 --- a/dpsim-models/include/dpsim-models/DP/DP_Ph3_SeriesSwitch.h +++ b/dpsim-models/include/dpsim-models/DP/DP_Ph3_SeriesSwitch.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include namespace CPS { namespace DP { @@ -27,7 +27,10 @@ namespace Ph3 { class SeriesSwitch : public MNASimPowerComp, public Base::Ph1::Switch, public SharedFactory, - public MNASwitchInterface { + public MNASwitchInterface, + public MNAVariableCompInterface { +protected: + Bool mPrevState = false; public: /// Defines UID, name and logging level @@ -68,6 +71,9 @@ class SeriesSwitch : public MNASimPowerComp, Attribute::Ptr &leftVector) override; void mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) override; + + // #### MNA section for variable component #### + Bool hasParameterChanged() override; }; } // namespace Ph3 } // namespace DP diff --git a/dpsim-models/include/dpsim-models/Definitions.h b/dpsim-models/include/dpsim-models/Definitions.h index 88eec7e6b8..cd1481334f 100644 --- a/dpsim-models/include/dpsim-models/Definitions.h +++ b/dpsim-models/include/dpsim-models/Definitions.h @@ -92,8 +92,6 @@ typedef Eigen::PartialPivLU LUFactorized; /// typedef Eigen::SparseLU LUFactorizedSparse; /// -typedef Eigen::Matrix Vector; -/// template using MatrixVar = Eigen::Matrix; diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Inductor.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Inductor.h index d87769454c..9e953b2575 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Inductor.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Inductor.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace CPS { namespace EMT { @@ -24,6 +24,7 @@ namespace Ph1 { /// frequency and the current source changes for each iteration. class Inductor : public MNASimPowerComp, public Base::Ph1::Inductor, + public MNATearInterface, public SharedFactory { protected: /// DC equivalent current source [A] @@ -74,6 +75,12 @@ class Inductor : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; + + // #### Tearing methods #### + void mnaTearInitialize(Real omega, Real timestep) override; + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; + void mnaTearApplyVoltageStamp(Matrix &voltageVector) override; + void mnaTearPostStep(Complex voltage, Complex current) override; }; } // namespace Ph1 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_PiLine.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_PiLine.h new file mode 100644 index 0000000000..0e16386a63 --- /dev/null +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_PiLine.h @@ -0,0 +1,85 @@ +/* Author: Christoph Wirtz + * SPDX-FileCopyrightText: 2025 FGH e.V. + * SPDX-License-Identifier: MPL-2.0 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace CPS { +namespace EMT { +namespace Ph1 { +/// \brief PI-line dynamic phasor model +/// +/// This model consists sub components to represent the +/// RLC elements of a PI-line. +class PiLine : public CompositePowerComp, + public MNATearInterface, + public Base::Ph1::PiLine, + public SharedFactory { +protected: + /// Series Inductance submodel + std::shared_ptr mSubSeriesInductor; + /// Series Resistor submodel + std::shared_ptr mSubSeriesResistor; + /// Parallel Resistor submodel at Terminal 0 + std::shared_ptr mSubParallelResistor0; + // Parallel Capacitor submodel at Terminal 0 + std::shared_ptr mSubParallelCapacitor0; + /// Parallel resistor submodel at Terminal 1 + std::shared_ptr mSubParallelResistor1; + // Parallel capacitor submodel at Terminal 1 + std::shared_ptr mSubParallelCapacitor1; + /// solver + std::vector mRightVectorStamps; + +public: + /// Defines UID, name and logging level + PiLine(String uid, String name, Logger::Level logLevel = Logger::Level::off); + /// Defines name and logging level + PiLine(String name, Logger::Level logLevel = Logger::Level::off) + : PiLine(name, name, logLevel) {} + + SimPowerComp::Ptr clone(String copySuffix) override; + + // #### General #### + /// Initializes component from power flow data + void initializeFromNodesAndTerminals(Real frequency) override; + + // #### MNA section #### + /// Updates internal current variable of the component + void mnaCompUpdateCurrent(const Matrix &leftVector) override; + /// Updates internal voltage variable of the component + void mnaCompUpdateVoltage(const Matrix &leftVector) override; + /// MNA pre step operations + void mnaParentPreStep(Real time, Int timeStepCount) override; + /// MNA post step operations + void mnaParentPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; + /// Add MNA pre step dependencies + void mnaParentAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; + /// Add MNA post step dependencies + void + mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; + + MNAInterface::List mnaTearGroundComponents() override; + void mnaTearInitialize(Real omega, Real timeStep) override; + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; + void mnaTearApplyVoltageStamp(Matrix &voltageVector) override; + void mnaTearPostStep(Complex voltage, Complex current) override; +}; +} // namespace Ph1 +} // namespace EMT +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Resistor.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Resistor.h index bb7f2947ab..70317ee77f 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Resistor.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Resistor.h @@ -12,7 +12,7 @@ #include #include -#include +#include namespace CPS { namespace EMT { @@ -20,6 +20,7 @@ namespace Ph1 { /// EMT Resistor class Resistor : public MNASimPowerComp, public Base::Ph1::Resistor, + public MNATearInterface, public SharedFactory { protected: public: @@ -56,6 +57,8 @@ class Resistor : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; + // #### MNA Tear Section #### + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; }; } // namespace Ph1 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSNTypeI2T.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSNTypeI2T.h new file mode 100644 index 0000000000..3494ab6aa7 --- /dev/null +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSNTypeI2T.h @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include +#include + +namespace CPS { +namespace EMT { +namespace Ph1 { +/// \brief SSNTypeI2T +/// Model for a one phase, two terminal I-type SSN component which can be represented using +/// a state space equation system +/// x' = A * x + B * u +/// y = C * x + D * u +/// with x: state vector, y: output vector, u: input vector, +/// where u represents external current (mIntfCurrent), +/// y represents external voltage (mIntfVoltage), +/// x represents any component states. +class SSNTypeI2T : public MNASimPowerComp, + public SharedFactory { +private: + void ssnUpdateState(); + void setSSNMatricesToZero(); + +protected: + Matrix mX; + Matrix mU; + Matrix mUOld; + Matrix mW; + Matrix mYHist; + +public: + const CPS::Attribute::Ptr mA; + const CPS::Attribute::Ptr mB; + const CPS::Attribute::Ptr mC; + const CPS::Attribute::Ptr mD; + + const CPS::Attribute::Ptr mdA; + const CPS::Attribute::Ptr mdB; + const CPS::Attribute::Ptr mdC; + + /// Defines UID, name, component parameters and logging level + SSNTypeI2T(String uid, String name, + Logger::Level logLevel = Logger::Level::off); + /// Defines name and logging level + SSNTypeI2T(String name, Logger::Level logLevel = Logger::Level::off) + : SSNTypeI2T(name, name, logLevel) {} + + SimPowerComp::Ptr clone(String name) override; + + void manualInit(Matrix initialState, Matrix initialInput, + Matrix initialOldInput, Real initCurrent, Real initVoltage); + // #### General #### + void setParameters(const Matrix A, const Matrix B, const Matrix C, + const Matrix D); + /// Initializes component from power flow data + void initializeFromNodesAndTerminals(Real frequency) override; + + // #### MNA section #### + /// Initializes internal variables of the component + void mnaCompInitialize(Real omega, Real timeStep, + Attribute::Ptr leftVector) override; + /// Stamps system matrix + void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override; + /// Stamps right side (source) vector + void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override; + /// Update interface voltage from MNA system result + void mnaCompUpdateVoltage(const Matrix &leftVector) override; + /// Update interface current from MNA system result + void mnaCompUpdateCurrent(const Matrix &leftVector) override; + + void mnaCompPreStep(Real time, Int timeStepCount) override; + void mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; + + /// Add MNA pre step dependencies + void mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; + + /// Add MNA post step dependencies + void + mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; +}; +} // namespace Ph1 +} // namespace EMT +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSNTypeV2T.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSNTypeV2T.h new file mode 100644 index 0000000000..078bd8c54e --- /dev/null +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSNTypeV2T.h @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include +#include + +namespace CPS { +namespace EMT { +namespace Ph1 { +/// \brief SSNTypeV2T +/// Model for a one phase, two terminal V-type SSN component which can be represented using +/// a state space equation system +/// x' = A * x + B * u +/// y = C * x + D * u +/// with x: state vector, y: output vector, u: input vector, +/// where u represents external voltage (mIntfVoltage), +/// y represents external current (mIntfCurrent), +/// x represents any component states. +class SSNTypeV2T : public MNASimPowerComp, + public SharedFactory { +private: + void ssnUpdateState(); + void setSSNMatricesToZero(); + +protected: + Matrix mX; + Matrix mU; + Matrix mUOld; + Matrix mW; + Matrix mYHist; + +public: + const CPS::Attribute::Ptr mA; + const CPS::Attribute::Ptr mB; + const CPS::Attribute::Ptr mC; + const CPS::Attribute::Ptr mD; + + const CPS::Attribute::Ptr mdA; + const CPS::Attribute::Ptr mdB; + const CPS::Attribute::Ptr mdC; + + /// Defines UID, name, component parameters and logging level + SSNTypeV2T(String uid, String name, + Logger::Level logLevel = Logger::Level::off); + /// Defines name and logging level + SSNTypeV2T(String name, Logger::Level logLevel = Logger::Level::off) + : SSNTypeV2T(name, name, logLevel) {} + + SimPowerComp::Ptr clone(String name) override; + + void manualInit(Matrix initialState, Matrix initialInput, + Matrix initialOldInput, Real initCurrent, Real initVoltage); + + // #### General #### + void setParameters(const Matrix A, const Matrix B, const Matrix C, + const Matrix D); + /// Initializes component from power flow data + void initializeFromNodesAndTerminals(Real frequency) override; + + // #### MNA section #### + /// Initializes internal variables of the component + void mnaCompInitialize(Real omega, Real timeStep, + Attribute::Ptr leftVector) override; + /// Stamps system matrix + void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override; + /// Stamps right side (source) vector + void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override; + /// Update interface voltage from MNA system result + void mnaCompUpdateVoltage(const Matrix &leftVector) override; + /// Update interface current from MNA system result + void mnaCompUpdateCurrent(const Matrix &leftVector) override; + + void mnaCompPreStep(Real time, Int timeStepCount) override; + void mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; + + /// Add MNA pre step dependencies + void mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; + + /// Add MNA post step dependencies + void + mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; +}; +} // namespace Ph1 +} // namespace EMT +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSN_Full_Serial_RLC.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSN_Full_Serial_RLC.h new file mode 100644 index 0000000000..9a83abcef8 --- /dev/null +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_SSN_Full_Serial_RLC.h @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include +#include +#include +#include +#include + +namespace CPS { +namespace EMT { +namespace Ph1 { +namespace SSN { +/// \brief Full_Serial_RLC +/// +/// This element represents an one port circuit consisting of a resistor, +/// an inductor and a capacitor connected in series. The terminals are at +/// the beginning and the end of the component chain. +/// The states are the capacitor voltage and the inductor current, the output +/// is the latter of those states (inductor current). The input is the voltage +/// across the whole circuit. States and past inputs are updated after each +/// time step and are used to calculate the current (input) voltage, +/// represented as MNA node voltages. +/// SSN theory and variable naming based on +/// C. Dufour, J. Mahseredjian and J. Belanger, +/// "A combined state-space nodal method for the simulation of power system +/// transients," 2011 IEEE Power and Energy Society General Meeting, Detroit, +/// MI, USA, 2011, pp. 1-1, doi: 10.1109/PES.2011.6038887. keywords: +/// {Mathematical model;Analytical models;Equations;Power system transients; +/// Couplings;Switching circuits} + +class Full_Serial_RLC final : public MNASimPowerComp, + public SharedFactory, + public Base::Ph1::Resistor, + public Base::Ph1::Inductor, + public Base::Ph1::Capacitor { +public: + /// Defines UID, name, component parameters and logging level + Full_Serial_RLC(String uid, String name, + Logger::Level logLevel = Logger::Level::off); + /// Defines name and logging level + Full_Serial_RLC(String name, Logger::Level logLevel = Logger::Level::off) + : Full_Serial_RLC(name, name, logLevel) {} + + SimPowerComp::Ptr clone(String name) override; + void setParameters(Real resistance, Real inductance, Real capacitance); + + // #### General #### + /// Initializes component from power flow data + void initializeFromNodesAndTerminals(Real frequency) override; + + // #### MNA section #### + /// Initializes internal variables of the component + void mnaCompInitialize(Real omega, Real timeStep, + Attribute::Ptr leftVector) override; + /// Stamps system matrix + void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override; + /// Stamps right side (source) vector + void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override; + /// Update interface voltage from MNA system result + void mnaCompUpdateVoltage(const Matrix &leftVector) override; + /// Update interface current from MNA system result + void mnaCompUpdateCurrent(const Matrix &leftVector) override; + /// MNA pre step operations + void mnaCompPreStep(Real time, Int timeStepCount) override; + /// MNA post step operations + void mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; + /// Add MNA pre step dependencies + void mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; + /// Add MNA post step dependencies + void + mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; + +private: + Matrix mState = Matrix::Zero(2, 1); + Real mYHistory = 0; + + Real mDufourUNT = 0; + + Matrix mDufourAKHat = Matrix::Zero(2, 2); + Matrix mDufourBKHat = Matrix::Zero(2, 1); + Matrix mDufourBKNHat = Matrix::Zero(2, 1); + Real mDufourWKN = 0; + Matrix mDufourCKN = Matrix::Zero(1, 2); + + void ssnUpdateState(); +}; +} // namespace SSN +} // namespace Ph1 +} // namespace EMT +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Switch.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Switch.h index d78ffd1bc1..ae1397362a 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Switch.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Switch.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include namespace CPS { namespace EMT { @@ -25,8 +25,8 @@ namespace Ph1 { class Switch : public MNASimPowerComp, public Base::Ph1::Switch, public SharedFactory, + public MNAVariableCompInterface, public MNASwitchInterface { - public: /// Defines UID, name, component parameters and logging level Switch(String uid, String name, Logger::Level loglevel = Logger::Level::off); @@ -69,6 +69,8 @@ class Switch : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; + // #### MNA section for variable component #### + Bool hasParameterChanged() override; }; } // namespace Ph1 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.h index 5fd7dd2572..d1f8bee5b1 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.h @@ -72,13 +72,6 @@ class AvVoltSourceInverterStateSpace protected: Matrix mIfabc = Matrix::Zero(3, 1); - /*Real mIfa; - Real mIfb; - Real mIfc;*/ - - /*Real mVca; - Real mVcb; - Real mVcc;*/ // Norton equivalant voltage source Matrix mEquivCurrent = Matrix::Zero(3, 1); @@ -111,13 +104,6 @@ class AvVoltSourceInverterStateSpace void initializeStates(Real omega, Real timeStep, Attribute::Ptr leftVector); - // initialize with parameters. - //void initialize(Real theta, Real phi_pll, Real p, Real q, Real phi_d, Real phi_q, - // Real gamma_d, Real gamma_q, Real i_fd, Real i_fq, Real v_cd, Real v_cq); - - //void initStates(Real initOmegaPLL, Real initPhiPLL, Real initP, Real initQ, - // Real initPhid, Real initPhiQ, Real initGamma_d, Real initGamma_q, Real initVcabc, Real initIfabc); - void updateStates(); void setParameters(Real sysOmega, Complex sysVoltNom, Real Pref, Real Qref, diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledCurrentSource.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledCurrentSource.h index de9f59839c..03189ce68e 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledCurrentSource.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledCurrentSource.h @@ -21,7 +21,8 @@ namespace Ph3 { /// /// This model uses modified nodal analysis to represent an ideal current source. /// This involves the stamping of the current to the right side vector. -class ControlledCurrentSource : public MNASimPowerComp, public SharedFactory { +class ControlledCurrentSource : public MNASimPowerComp, + public SharedFactory { protected: // Updates current according to reference phasor and frequency void updateCurrent(Real time); @@ -30,9 +31,12 @@ class ControlledCurrentSource : public MNASimPowerComp, public SharedFacto const Attribute::Ptr mCurrentRef; /// Defines UID, name and logging level - ControlledCurrentSource(String uid, String name, Logger::Level logLevel = Logger::Level::off); + ControlledCurrentSource(String uid, String name, + Logger::Level logLevel = Logger::Level::off); /// - ControlledCurrentSource(String name, Logger::Level logLevel = Logger::Level::off) : ControlledCurrentSource(name, name, logLevel) {} + ControlledCurrentSource(String name, + Logger::Level logLevel = Logger::Level::off) + : ControlledCurrentSource(name, name, logLevel) {} SimPowerComp::Ptr clone(String name) override; // #### General #### @@ -42,7 +46,8 @@ class ControlledCurrentSource : public MNASimPowerComp, public SharedFacto void setParameters(Matrix currentRef); // #### MNA section #### /// Initializes internal variables of the component - void mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) override; + void mnaCompInitialize(Real omega, Real timeStep, + Attribute::Ptr leftVector) override; /// Stamps right side (source) vector void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override; /// Returns voltage through the component @@ -50,12 +55,19 @@ class ControlledCurrentSource : public MNASimPowerComp, public SharedFacto /// MNA pre step operations void mnaCompPreStep(Real time, Int timeStepCount) override; /// MNA post step operations - void mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) override; + void mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; /// Add MNA pre step dependencies - void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override; + void mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; /// Add MNA post step dependencies - void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector) override; + void + mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledVoltageSource.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledVoltageSource.h index fbd45334b8..32b7bd8fa8 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledVoltageSource.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_ControlledVoltageSource.h @@ -21,7 +21,8 @@ namespace Ph3 { /// /// This model uses modified nodal analysis to represent an ideal voltage source. /// This voltage source derives it's output purely from attributes rather than an internal signal generator. -class ControlledVoltageSource : public MNASimPowerComp, public SharedFactory { +class ControlledVoltageSource : public MNASimPowerComp, + public SharedFactory { protected: // Updates voltage according to reference phasor and frequency void updateVoltage(Real time); @@ -30,9 +31,12 @@ class ControlledVoltageSource : public MNASimPowerComp, public SharedFacto const CPS::Attribute::Ptr mVoltageRef; /// Defines UID, name and logging level - ControlledVoltageSource(String uid, String name, Logger::Level logLevel = Logger::Level::off); + ControlledVoltageSource(String uid, String name, + Logger::Level logLevel = Logger::Level::off); /// - ControlledVoltageSource(String name, Logger::Level logLevel = Logger::Level::off) : ControlledVoltageSource(name, name, logLevel) {} + ControlledVoltageSource(String name, + Logger::Level logLevel = Logger::Level::off) + : ControlledVoltageSource(name, name, logLevel) {} SimPowerComp::Ptr clone(String name) override; // #### General #### @@ -45,7 +49,8 @@ class ControlledVoltageSource : public MNASimPowerComp, public SharedFacto // #### MNA section #### /// Initializes internal variables of the component - void mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) override; + void mnaCompInitialize(Real omega, Real timeStep, + Attribute::Ptr leftVector) override; /// Stamps system matrix void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override; /// Stamps right side (source) vector @@ -55,12 +60,19 @@ class ControlledVoltageSource : public MNASimPowerComp, public SharedFacto /// MNA pre step operations void mnaCompPreStep(Real time, Int timeStepCount) override; /// MNA post step operations - void mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) override; + void mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) override; /// Add MNA pre step dependencies - void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override; + void mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) override; /// Add MNA post step dependencies - void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector) override; + void + mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Inductor.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Inductor.h index 04f50a0214..67cf010697 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Inductor.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Inductor.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace CPS { namespace EMT { @@ -24,6 +24,7 @@ namespace Ph3 { /// frequency and the current source changes for each iteration. class Inductor : public MNASimPowerComp, public Base::Ph3::Inductor, + public MNATearInterface, public SharedFactory { protected: /// DC equivalent current source [A] @@ -73,6 +74,11 @@ class Inductor : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; + // #### MNA Tear Section #### + void mnaTearInitialize(Real omega, Real timestep) override; + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; + void mnaTearApplyVoltageStamp(Matrix &voltageVector) override; + void mnaTearPostStep(MatrixComp voltage, MatrixComp current) override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_PiLine.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_PiLine.h index 588c3a91c2..c494bd2265 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_PiLine.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_PiLine.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace CPS { namespace EMT { @@ -23,6 +23,7 @@ namespace Ph3 { /// This model consists sub components to represent the /// RLC elements of a PI-line. class PiLine : public CompositePowerComp, + public MNATearInterface, public Base::Ph3::PiLine, public SharedFactory { protected: @@ -76,11 +77,11 @@ class PiLine : public CompositePowerComp, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; - //MNAInterface::List mnaTearGroundComponents(); - /*void mnaTearInitialize(Real omega, Real timeStep); - void mnaTearApplyMatrixStamp(SparseMatrixRow& tearMatrix); - void mnaTearApplyVoltageStamp(Matrix& voltageVector); - void mnaTearPostStep(Matrix voltage, Matrix current);*/ + MNAInterface::List mnaTearGroundComponents() override; + void mnaTearInitialize(Real omega, Real timeStep) override; + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; + void mnaTearApplyVoltageStamp(Matrix &voltageVector) override; + void mnaTearPostStep(MatrixComp voltage, MatrixComp current) override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_RXLoad.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_RXLoad.h index 1fbdf00bcc..febf754aaf 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_RXLoad.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_RXLoad.h @@ -59,9 +59,14 @@ class RXLoad : public CompositePowerComp, public SharedFactory { Logger::Level logLevel = Logger::Level::off); // #### General #### - virtual String description() override { return fmt::format("Active: {}MW, Reactive: {}MVAr, Voltage: {}kV", (**mActivePower)(0, 0) / 1e6, (**mReactivePower)(0, 0) / 1e6, (**mNomVoltage) / 1e3); }; + virtual String description() override { + return fmt::format("Active: {}MW, Reactive: {}MVAr, Voltage: {}kV", + (**mActivePower)(0, 0) / 1e6, + (**mReactivePower)(0, 0) / 1e6, (**mNomVoltage) / 1e3); + }; /// - void setParameters(Matrix activePower, Matrix reactivePower, Real volt, bool reactanceInSeries = false); + void setParameters(Matrix activePower, Matrix reactivePower, Real volt, + bool reactanceInSeries = false); /// Initializes component from power flow data void initializeFromNodesAndTerminals(Real frequency) override; diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Resistor.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Resistor.h index a82a4c1638..d5a9333d7f 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Resistor.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Resistor.h @@ -10,13 +10,14 @@ #include #include -#include +#include namespace CPS { namespace EMT { namespace Ph3 { /// EMT Resistor class Resistor : public MNASimPowerComp, public Base::Ph3::Resistor, + public MNATearInterface, public SharedFactory { protected: public: @@ -29,33 +30,36 @@ class Resistor : public MNASimPowerComp, // #### General #### /// - SimPowerComp::Ptr clone(String name); + SimPowerComp::Ptr clone(String name) override; /// Initializes component from power flow data - void initializeFromNodesAndTerminals(Real frequency); + void initializeFromNodesAndTerminals(Real frequency) override; /// enable DP to EMT bach transformation void enableBackShift(); // #### MNA section #### /// Initializes internal variables of the component void mnaCompInitialize(Real omega, Real timeStep, - Attribute::Ptr leftSideVector); + Attribute::Ptr leftSideVector) override; /// Stamps system matrix - void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix); + void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override; /// Stamps right side (source) vector - void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) {} + void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override {} /// Update interface voltage from MNA system result - void mnaCompUpdateVoltage(const Matrix &leftVector); + void mnaCompUpdateVoltage(const Matrix &leftVector) override; /// Update interface current from MNA system result - void mnaCompUpdateCurrent(const Matrix &leftVector); + void mnaCompUpdateCurrent(const Matrix &leftVector) override; /// MNA pre and post step operations void mnaCompPostStep(Real time, Int timeStepCount, - Attribute::Ptr &leftVector); + Attribute::Ptr &leftVector) override; /// add MNA pre and post step dependencies void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector); + Attribute::Ptr &leftVector) override; + + // #### MNA Tear Section #### + void mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Full_Serial_RLC.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Full_Serial_RLC.h index 145109cbe0..3b9eb3a2ec 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Full_Serial_RLC.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Full_Serial_RLC.h @@ -94,4 +94,4 @@ class Full_Serial_RLC final : public MNASimPowerComp, } // namespace SSN } // namespace Ph3 } // namespace EMT -} // namespace CPS \ No newline at end of file +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Inductor.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Inductor.h index a1e1871496..400b8857f4 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Inductor.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SSN_Inductor.h @@ -83,4 +83,4 @@ class Inductor final : public MNASimPowerComp, } // namespace SSN } // namespace Ph3 } // namespace EMT -} // namespace CPS \ No newline at end of file +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SeriesSwitch.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SeriesSwitch.h index 8111aea776..7034db6a69 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SeriesSwitch.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_SeriesSwitch.h @@ -10,8 +10,8 @@ #include #include -#include #include +#include namespace CPS { namespace EMT { @@ -25,7 +25,10 @@ namespace Ph3 { class SeriesSwitch : public MNASimPowerComp, public Base::Ph1::Switch, public SharedFactory, + public MNAVariableCompInterface, public MNASwitchInterface { +protected: + Bool mPrevState = false; public: /// Defines UID, name and log level @@ -68,6 +71,9 @@ class SeriesSwitch : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; + + // #### MNA section for variable component #### + Bool hasParameterChanged() override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Switch.h b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Switch.h index 9dc44c0d08..77a378d518 100644 --- a/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Switch.h +++ b/dpsim-models/include/dpsim-models/EMT/EMT_Ph3_Switch.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include namespace CPS { namespace EMT { @@ -25,8 +25,8 @@ namespace Ph3 { class Switch : public MNASimPowerComp, public Base::Ph3::Switch, public SharedFactory, + public MNAVariableCompInterface, public MNASwitchInterface { - public: /// Defines UID, name, component parameters and logging level Switch(String uid, String name, Logger::Level loglevel = Logger::Level::off); @@ -69,6 +69,9 @@ class Switch : public MNASimPowerComp, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute::Ptr &leftVector) override; + + // #### MNA section for variable component #### + Bool hasParameterChanged() override; }; } // namespace Ph3 } // namespace EMT diff --git a/dpsim-models/include/dpsim-models/Factory.h b/dpsim-models/include/dpsim-models/Factory.h index 703b7ca0ec..273928d164 100644 --- a/dpsim-models/include/dpsim-models/Factory.h +++ b/dpsim-models/include/dpsim-models/Factory.h @@ -132,4 +132,4 @@ void registerSynchronGenerators() { } } // namespace Ph1 } // namespace DP -} // namespace SynchronGeneratorFactory \ No newline at end of file +} // namespace SynchronGeneratorFactory diff --git a/dpsim-models/include/dpsim-models/Filesystem.h b/dpsim-models/include/dpsim-models/Filesystem.h index df13e828aa..43eef985e5 100644 --- a/dpsim-models/include/dpsim-models/Filesystem.h +++ b/dpsim-models/include/dpsim-models/Filesystem.h @@ -6,6 +6,8 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. *********************************************************************************/ +#pragma once + #ifndef USE_GHC_FS #include namespace fs = std::experimental::filesystem; @@ -13,3 +15,9 @@ namespace fs = std::experimental::filesystem; #include namespace fs = ghc::filesystem; #endif + +#include + +#if FMT_VERSION >= 90000 +template <> class fmt::formatter : public fmt::ostream_formatter {}; +#endif diff --git a/dpsim-models/include/dpsim-models/Graph.h b/dpsim-models/include/dpsim-models/Graph.h index 894d0fedf2..773192685a 100644 --- a/dpsim-models/include/dpsim-models/Graph.h +++ b/dpsim-models/include/dpsim-models/Graph.h @@ -45,10 +45,7 @@ class Edge : public Element { Edge(Graph *g, const String &name, Node *head, Node *tail); }; -/** - * - * See: http://www.graphviz.org/pdf/libguide.pdf - */ +// See: http://www.graphviz.org/pdf/libguide.pdf class Graph : public Element { protected: diff --git a/dpsim-models/include/dpsim-models/Logger.h b/dpsim-models/include/dpsim-models/Logger.h index ac42949ee3..421ac22a66 100644 --- a/dpsim-models/include/dpsim-models/Logger.h +++ b/dpsim-models/include/dpsim-models/Logger.h @@ -69,3 +69,50 @@ class Logger { static String getCSVLineFromData(Real time, const MatrixComp &data); }; } // namespace CPS + +#if FMT_VERSION >= 90000 +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter { +}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +template <> +class fmt::formatter : public fmt::ostream_formatter { +}; +template +class fmt::formatter> : public fmt::ostream_formatter { +}; +template +class fmt::formatter> + : public fmt::ostream_formatter {}; +template +class fmt::formatter> + : public fmt::ostream_formatter {}; + +template <> +class fmt::formatter> + : public fmt::ostream_formatter {}; +template <> +class fmt::formatter> + : public fmt::ostream_formatter {}; +#endif diff --git a/dpsim-models/include/dpsim-models/MNAStampUtils.h b/dpsim-models/include/dpsim-models/MNAStampUtils.h index d3372bf41b..ccb065fe51 100644 --- a/dpsim-models/include/dpsim-models/MNAStampUtils.h +++ b/dpsim-models/include/dpsim-models/MNAStampUtils.h @@ -30,10 +30,10 @@ class MNAStampUtils { const Matrix &conductanceMat, SparseMatrixRow &mat, UInt node1Index, UInt node2Index, const Logger::Log &mSLog); - static void stamp3x3ConductanceMatrixNodeToGround(const Matrix &conductanceMat, - SparseMatrixRow &mat, - UInt nodeIndex, - const Logger::Log &mSLog); + static void + stamp3x3ConductanceMatrixNodeToGround(const Matrix &conductanceMat, + SparseMatrixRow &mat, UInt nodeIndex, + const Logger::Log &mSLog); static void stampAdmittanceMatrix( const MatrixComp &admittanceMat, SparseMatrixRow &mat, UInt node1Index, @@ -101,4 +101,4 @@ class MNAStampUtils { Int maxFreq, Int freqIdx, const Logger::Log &mSLog); }; -} // namespace CPS \ No newline at end of file +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/MathUtils.h b/dpsim-models/include/dpsim-models/MathUtils.h index 6841df8ebc..0f091827db 100644 --- a/dpsim-models/include/dpsim-models/MathUtils.h +++ b/dpsim-models/include/dpsim-models/MathUtils.h @@ -119,6 +119,10 @@ class Math { const Matrix &C, const Real &dt, Matrix &Ad, Matrix &Bd, Matrix &Cd); + static void calculateStateSpaceTrapezoidalMatrices(const Matrix &A, + const Matrix &B, + const Real &dt, Matrix &Ad, + Matrix &Bd); /// Apply the trapezoidal based state space matrices Ad, Bd, Cd to get the states at the current time step static Matrix applyStateSpaceTrapezoidalMatrices(const Matrix &Ad, const Matrix &Bd, diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_AvVoltageSourceInverterDQ.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_AvVoltageSourceInverterDQ.h index 481a915bc3..a914470af6 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_AvVoltageSourceInverterDQ.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_AvVoltageSourceInverterDQ.h @@ -25,6 +25,10 @@ class AvVoltageSourceInverterDQ : public CompositePowerComp, public Base::AvVoltageSourceInverterDQ, public SharedFactory { +private: + /// Nominal voltage + Real mVnom; + protected: // ### General Parameters ### /// Nominal system angle @@ -65,8 +69,6 @@ class AvVoltageSourceInverterDQ // ### General Parameters ### /// Nominal frequency const Attribute::Ptr mOmegaN; - /// Nominal voltage - const Attribute::Ptr mVnom; /// Active power reference const Attribute::Ptr mPref; /// Reactive power reference @@ -127,6 +129,10 @@ class AvVoltageSourceInverterDQ Real gamma_qInit); void withControl(Bool controlOn) { mWithControl = controlOn; }; + // #### Powerflow section #### + /// Get nominal voltage + Real getNomVoltage() const; + // #### MNA section #### /// Initializes internal variables of the component void mnaParentInitialize(Real omega, Real timeStep, diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_Load.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_Load.h index 0a27f08750..e8749a6b46 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_Load.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_Load.h @@ -25,8 +25,6 @@ class Load : public CompositePowerComp, public SharedFactory, public PFSolverInterfaceBus { public: - /// Nominal voltage [V] - const Attribute::Ptr mNomVoltage; /// Active power [Watt] const Attribute::Ptr mActivePower; /// Reactive power [VAr] @@ -37,6 +35,8 @@ class Load : public CompositePowerComp, const Attribute::Ptr mReactivePowerPerUnit; private: + /// Nominal voltage [V] + Real mNomVoltage; /// base apparent power[VA] Real mBaseApparentPower; ///base omega [1/s] @@ -79,6 +79,8 @@ class Load : public CompositePowerComp, void updatePQ(Real time); // #### Powerflow section #### + /// Get nominal voltage + Real getNomVoltage() const; /// Calculates component's parameters in specified per-unit system void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega); /// Modify powerflow bus type diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h index f86f2ed20a..ee8220b47f 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_NetworkInjection.h @@ -71,6 +71,8 @@ class NetworkInjection : public CompositePowerComp, // #### Powerflow section #### /// Set parameters relevant for PF solver void setParameters(Real vSetPointPerUnit); + // Get base voltage + Real getBaseVoltage() const; /// Set base voltage void setBaseVoltage(Real baseVoltage); /// Calculates component's parameters in specified per-unit system diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_PiLine.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_PiLine.h index f99d2e5fb7..5bd3aa6993 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_PiLine.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_PiLine.h @@ -28,10 +28,11 @@ class PiLine : public CompositePowerComp, public MNATearInterface, public SharedFactory, public PFSolverInterfaceBranch { -public: - ///base voltage [V] - const Attribute::Ptr mBaseVoltage; +private: + /// base voltage [V] + Real mBaseVoltage; +public: // #### Power flow results #### /// branch Current flow [A], coef(0) has data from node 0, coef(1) from node 1. const Attribute::Ptr mCurrent; @@ -106,6 +107,8 @@ class PiLine : public CompositePowerComp, void initializeFromNodesAndTerminals(Real frequency) override; // #### Powerflow section #### + /// Get base voltage + Real getBaseVoltage() const; /// Set base voltage void setBaseVoltage(Real baseVoltage); /// Calculates component's parameters in specified per-unit system diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_RXLine.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_RXLine.h index 37ac353e77..65735b3425 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_RXLine.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_RXLine.h @@ -22,6 +22,10 @@ class RXLine : public CompositePowerComp, public SharedFactory, public PFSolverInterfaceBranch, public Base::Ph1::PiLine { +private: + ///base voltage [V] + Real mBaseVoltage; + protected: /// CHECK: Which of these really need to be member variables? ///Capacitance of the line in [F] @@ -59,8 +63,6 @@ class RXLine : public CompositePowerComp, std::shared_ptr mInitialResistor; public: - ///base voltage [V] - const Attribute::Ptr mBaseVoltage; ///Inductance of the line in [H] /// CHECK: Why does this not use the base class' attribute mSeriesInd? const Attribute::Ptr mInductance; @@ -100,9 +102,10 @@ class RXLine : public CompositePowerComp, void transformParametersToPerUnitSystem(); // #### Powerflow section #### + /// Get base voltage + Real getBaseVoltage() const; /// Stamps admittance matrix void pfApplyAdmittanceMatrixStamp(SparseMatrixCompRow &Y) override; - /// updates branch current and power flow, input pu value, update with real value void updateBranchFlow(VectorComp ¤t, VectorComp &powerflow); /// stores nodal injection power in this line object diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_Switch.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_Switch.h index a709663225..e1ab02c763 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_Switch.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_Switch.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include namespace CPS { namespace SP { @@ -25,6 +25,7 @@ namespace Ph1 { class Switch : public MNASimPowerComp, public Base::Ph1::Switch, public SharedFactory, + public MNAVariableCompInterface, public MNASwitchInterface { public: @@ -68,6 +69,9 @@ class Switch : public MNASimPowerComp, void mnaCompApplySwitchSystemMatrixStamp(Bool closed, SparseMatrixRow &systemMatrix, Int freqIdx) override; + + // #### MNA section for variable component #### + Bool hasParameterChanged() override; }; } // namespace Ph1 } // namespace SP diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_SynchronGenerator.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_SynchronGenerator.h index 30ad1c09f9..332bb0cb15 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_SynchronGenerator.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_SynchronGenerator.h @@ -20,6 +20,8 @@ class SynchronGenerator : public SimPowerComp, public SharedFactory, public PFSolverInterfaceBus { private: + /// Base voltage [V] + Real mBaseVoltage; /// Base apparent power[VA] Real mBaseApparentPower; @@ -30,8 +32,6 @@ class SynchronGenerator : public SimPowerComp, const Attribute::Ptr mSetPointReactivePower; /// Voltage set point of the machine [V] const Attribute::Ptr mSetPointVoltage; - /// Base voltage [V] - const Attribute::Ptr mBaseVoltage; /// Active power set point of the machine [pu] const Attribute::Ptr mSetPointActivePowerPerUnit; /// Reactive power set point of the machine [pu] @@ -51,6 +51,7 @@ class SynchronGenerator : public SimPowerComp, PowerflowBusType powerflowBusType, Real setPointReactivepower = 0); // #### Powerflow section #### + Real getBaseVoltage() const; /// Set base voltage void setBaseVoltage(Real baseVoltage); /// Initializes component from power flow data diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_Transformer.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_Transformer.h index 99b6642453..65b9f63ba6 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_Transformer.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_Transformer.h @@ -134,7 +134,10 @@ class Transformer : public CompositePowerComp, void initializeFromNodesAndTerminals(Real frequency) override; // #### Powerflow section #### - /// Set base voltage + /// Get nominal voltage at end 1 + Real getNominalVoltageEnd1() const; + /// Get nominal voltage at end 2 + Real getNominalVoltageEnd2() const; void setBaseVoltage(Real baseVoltage); /// Initializes component from power flow data void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega); diff --git a/dpsim-models/include/dpsim-models/SP/SP_Ph1_varResSwitch.h b/dpsim-models/include/dpsim-models/SP/SP_Ph1_varResSwitch.h index c1585c9715..65c5d47aa4 100644 --- a/dpsim-models/include/dpsim-models/SP/SP_Ph1_varResSwitch.h +++ b/dpsim-models/include/dpsim-models/SP/SP_Ph1_varResSwitch.h @@ -31,7 +31,6 @@ class varResSwitch : public MNASimPowerComp, public SharedFactory { protected: - Bool mPrevState = false; Real mDeltaResClosed = 0; Real mDeltaResOpen = 1.5; Real mPrevRes; // previous resistance value to multiply with rate of change @@ -94,6 +93,7 @@ class varResSwitch : public MNASimPowerComp, SparseMatrixRow &systemMatrix, Int freqIdx); + // #### MNA section for variable component #### Bool hasParameterChanged(); }; } // namespace Ph1 diff --git a/dpsim-models/include/dpsim-models/Signal/DecouplingLineEMT_Ph3.h b/dpsim-models/include/dpsim-models/Signal/DecouplingLineEMT_Ph3.h new file mode 100644 index 0000000000..563f991c98 --- /dev/null +++ b/dpsim-models/include/dpsim-models/Signal/DecouplingLineEMT_Ph3.h @@ -0,0 +1,97 @@ +/* Copyright 2017-2021 Institute for Automation of Complex Power Systems, + * EONERC, RWTH Aachen University + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *********************************************************************************/ + +#pragma once + +#include "dpsim-models/Definitions.h" +#include "dpsim-models/EMT/EMT_Ph3_ControlledCurrentSource.h" +#include + +#include +#include +#include + +namespace CPS { +namespace Signal { +class DecouplingLineEMT_Ph3 : public SimSignalComp, + public SharedFactory { +protected: + Real mDelay; + Matrix mResistance = Matrix::Zero(3, 3); + Matrix mInductance = Matrix::Zero(3, 3); + Matrix mCapacitance = Matrix::Zero(3, 3); + Matrix mSurgeImpedance; + + std::shared_ptr mNode1, mNode2; + std::shared_ptr mRes1, mRes2; + std::shared_ptr mSrc1, mSrc2; + Attribute::Ptr mSrcCur1, mSrcCur2; + + // Ringbuffers for the values of previous timesteps + // TODO make these matrix attributes + Matrix mVolt1, mVolt2, mCur1, mCur2; + UInt mBufIdx = 0; + UInt mBufSize; + Real mAlpha; + + Matrix interpolate(Matrix &data); + +public: + typedef std::shared_ptr Ptr; + + const Attribute::Ptr mSrcCur1Ref; + const Attribute::Ptr mSrcCur2Ref; + + ///FIXME: workaround for dependency analysis as long as the states aren't attributes + const Attribute::Ptr mStates; + + DecouplingLineEMT_Ph3(String name, + Logger::Level logLevel = Logger::Level::info); + + void setParameters(SimNode::Ptr node1, SimNode::Ptr node2, + Matrix resistance, Matrix inductance, Matrix capacitance); + void initialize(Real omega, Real timeStep); + void step(Real time, Int timeStepCount); + void postStep(); + Task::List getTasks(); + IdentifiedObject::List getLineComponents(); + + class PreStep : public Task { + public: + PreStep(DecouplingLineEMT_Ph3 &line) + : Task(**line.mName + ".MnaPreStep"), mLine(line) { + mPrevStepDependencies.push_back(mLine.mStates); + mModifiedAttributes.push_back(mLine.mSrc1->mCurrentRef); + mModifiedAttributes.push_back(mLine.mSrc2->mCurrentRef); + } + + void execute(Real time, Int timeStepCount); + + private: + DecouplingLineEMT_Ph3 &mLine; + }; + + class PostStep : public Task { + public: + PostStep(DecouplingLineEMT_Ph3 &line) + : Task(**line.mName + ".PostStep"), mLine(line) { + mAttributeDependencies.push_back(mLine.mRes1->mIntfVoltage); + mAttributeDependencies.push_back(mLine.mRes1->mIntfCurrent); + mAttributeDependencies.push_back(mLine.mRes2->mIntfVoltage); + mAttributeDependencies.push_back(mLine.mRes2->mIntfCurrent); + mModifiedAttributes.push_back(mLine.mStates); + } + + void execute(Real time, Int timeStepCount); + + private: + DecouplingLineEMT_Ph3 &mLine; + }; +}; +} // namespace Signal +} // namespace CPS diff --git a/dpsim-models/include/dpsim-models/Solver/MNATearInterface.h b/dpsim-models/include/dpsim-models/Solver/MNATearInterface.h index 0782176437..511d8115bf 100644 --- a/dpsim-models/include/dpsim-models/Solver/MNATearInterface.h +++ b/dpsim-models/include/dpsim-models/Solver/MNATearInterface.h @@ -28,6 +28,8 @@ class MNATearInterface { virtual void mnaTearApplyVoltageStamp(Matrix ¤tVector) {} // Update the internal state based on the solution of the complete system virtual void mnaTearPostStep(Complex voltage, Complex current) {} + // Update the internal state based on the solution of the complete system + virtual void mnaTearPostStep(MatrixComp voltage, MatrixComp current) {} void mnaTearSetIdx(UInt compIdx) { mTearIdx = compIdx; } diff --git a/dpsim-models/include/dpsim-models/TopologicalPowerComp.h b/dpsim-models/include/dpsim-models/TopologicalPowerComp.h index 9155d02b26..8806232153 100644 --- a/dpsim-models/include/dpsim-models/TopologicalPowerComp.h +++ b/dpsim-models/include/dpsim-models/TopologicalPowerComp.h @@ -49,8 +49,8 @@ class TopologicalPowerComp : public IdentifiedObject { Logger::Level logLevel = Logger::Level::off) : IdentifiedObject(uid, name), /* We also want to set the CLI loglevel according to the logLevel - * std::max(Logger::Level::info, logLevel). But because of excessive - * logging to Level::info that is currently infeasible. */ + * std::max(Logger::Level::info, logLevel). But because of excessive + * logging to Level::info that is currently infeasible. */ mSLog(Logger::get(name, logLevel, Logger::Level::warn)), mLogLevel(logLevel) {} diff --git a/dpsim-models/include/dpsim-models/TopologicalSignalComp.h b/dpsim-models/include/dpsim-models/TopologicalSignalComp.h index f789b06b11..a423612bc4 100644 --- a/dpsim-models/include/dpsim-models/TopologicalSignalComp.h +++ b/dpsim-models/include/dpsim-models/TopologicalSignalComp.h @@ -31,8 +31,8 @@ class TopologicalSignalComp : public IdentifiedObject { Logger::Level logLevel = Logger::Level::off) : IdentifiedObject(uid, name), /* We also want to set the CLI loglevel according to the logLevel - * std::max(Logger::Level::info, logLevel). But because of excessive - * logging to Level::info that is currently infeasible. */ + * std::max(Logger::Level::info, logLevel). But because of excessive + * logging to Level::info that is currently infeasible. */ mSLog(Logger::get(name, logLevel, Logger::Level::warn)), mLogLevel(logLevel) {} diff --git a/dpsim-models/src/CIM/Reader.cpp b/dpsim-models/src/CIM/Reader.cpp index 427d1f9a55..2b1478f90b 100644 --- a/dpsim-models/src/CIM/Reader.cpp +++ b/dpsim-models/src/CIM/Reader.cpp @@ -16,6 +16,8 @@ using namespace CPS; using namespace CPS::CIM; + +using CIMPP::String; using CIMPP::UnitMultiplier; Reader::Reader(String name, Logger::Level logLevel, @@ -113,7 +115,10 @@ TopologicalPowerComp::Ptr Reader::mapComponent(BaseClass *obj) { if (CIMPP::EquivalentShunt *shunt = dynamic_cast(obj)) return mapEquivalentShunt(shunt); - + if (CIMPP::Disconnector *disc = dynamic_cast(obj)) + return mapDisconnector(disc); + if (CIMPP::Breaker *cb = dynamic_cast(obj)) + return mapBreaker(cb); return nullptr; } @@ -176,8 +181,8 @@ void Reader::parseFiles() { dynamic_cast(obj)) { // Check if object is already in equipment list - if (mPowerflowEquipment.find(idObj->mRID) == - mPowerflowEquipment.end()) { + const auto &rid = cimString(idObj->mRID); + if (mPowerflowEquipment.find(rid) == mPowerflowEquipment.end()) { TopologicalPowerComp::Ptr comp = mapComponent(obj); if (comp) mPowerflowEquipment.insert(std::make_pair(comp->uid(), comp)); @@ -240,12 +245,13 @@ void Reader::processSvVoltage(CIMPP::SvVoltage *volt) { mSLog, "SvVoltage references missing Topological Node, ignoring"); return; } - auto search = mPowerflowNodes.find(node->mRID); + const auto &nodeRid = cimString(node->mRID); + auto search = mPowerflowNodes.find(nodeRid); if (search == mPowerflowNodes.end()) { SPDLOG_LOGGER_WARN(mSLog, "SvVoltage references Topological Node {}" " missing from mTopNodes, ignoring", - node->mRID); + nodeRid); return; } @@ -260,27 +266,29 @@ void Reader::processSvVoltage(CIMPP::SvVoltage *volt) { << volt->angle.value << std::endl; } Real voltagePhase = volt->angle.value * PI / 180; - mPowerflowNodes[node->mRID]->setInitialVoltage( + mPowerflowNodes[nodeRid]->setInitialVoltage( std::polar(voltageAbs, voltagePhase)); SPDLOG_LOGGER_INFO( mSLog, "Node {} MatrixNodeIndex {}: {} V, {} deg", - mPowerflowNodes[node->mRID]->uid(), - mPowerflowNodes[node->mRID]->matrixNodeIndex(), - std::abs(mPowerflowNodes[node->mRID]->initialSingleVoltage()), - std::arg(mPowerflowNodes[node->mRID]->initialSingleVoltage()) * 180 / PI); + mPowerflowNodes[nodeRid]->uid(), + mPowerflowNodes[nodeRid]->matrixNodeIndex(), + std::abs(mPowerflowNodes[nodeRid]->initialSingleVoltage()), + std::arg(mPowerflowNodes[nodeRid]->initialSingleVoltage()) * 180 / PI); } void Reader::processSvPowerFlow(CIMPP::SvPowerFlow *flow) { CIMPP::Terminal *term = flow->Terminal; - mPowerflowTerminals[term->mRID]->setPower( + const auto &terminalRid = cimString(term->mRID); + + mPowerflowTerminals[terminalRid]->setPower( Complex(Reader::unitValue(flow->p.value, UnitMultiplier::M), Reader::unitValue(flow->q.value, UnitMultiplier::M))); - SPDLOG_LOGGER_WARN(mSLog, "Terminal {}: {} W + j {} Var", term->mRID, - mPowerflowTerminals[term->mRID]->singleActivePower(), - mPowerflowTerminals[term->mRID]->singleReactivePower()); + SPDLOG_LOGGER_WARN(mSLog, "Terminal {}: {} W + j {} Var", terminalRid, + mPowerflowTerminals[terminalRid]->singleActivePower(), + mPowerflowTerminals[terminalRid]->singleReactivePower()); } SystemTopology Reader::systemTopology() { @@ -327,32 +335,37 @@ Matrix::Index Reader::mapTopologicalNode(String mrid) { TopologicalPowerComp::Ptr Reader::mapEnergyConsumer(CIMPP::EnergyConsumer *consumer) { - SPDLOG_LOGGER_INFO(mSLog, " Found EnergyConsumer {}", consumer->name); + const auto &consumerName = cimString(consumer->name); + const auto &consumerRid = cimString(consumer->mRID); + + SPDLOG_LOGGER_INFO(mSLog, " Found EnergyConsumer {}", consumerName); if (mDomain == Domain::EMT) { if (mPhase == PhaseType::ABC) { - return std::make_shared(consumer->mRID, consumer->name, + return std::make_shared(consumerRid, consumerName, mComponentLogLevel); } else { SPDLOG_LOGGER_INFO(mSLog, " RXLoad for EMT not implemented yet"); - return std::make_shared(consumer->mRID, consumer->name, + return std::make_shared(consumerRid, consumerName, mComponentLogLevel); } } else if (mDomain == Domain::SP) { - auto load = std::make_shared(consumer->mRID, consumer->name, + auto load = std::make_shared(consumerRid, consumerName, mComponentLogLevel); // TODO: Use EnergyConsumer.P and EnergyConsumer.Q if available, overwrite if existent SvPowerFlow data - /* + Real p = 0; Real q = 0; - if (consumer->p.value){ - p = unitValue(consumer->p.value,UnitMultiplier::M); + if (consumer->p){ + p = unitValue(consumer->p,UnitMultiplier::M); } - if (consumer->q.value){ - q = unitValue(consumer->q.value,UnitMultiplier::M); + if (consumer->q){ + q = unitValue(consumer->q,UnitMultiplier::M); } - load->setParameters(p, q, 0); - */ + + Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(consumer); + load->setParameters(p, q, baseVoltage); + // P and Q values will be set according to SvPowerFlow data load->modifyPowerFlowBusType( @@ -361,18 +374,21 @@ Reader::mapEnergyConsumer(CIMPP::EnergyConsumer *consumer) { return load; } else { if (mUseProtectionSwitches) - return std::make_shared( - consumer->mRID, consumer->name, mComponentLogLevel); + return std::make_shared(consumerRid, consumerName, + mComponentLogLevel); else - return std::make_shared(consumer->mRID, consumer->name, + return std::make_shared(consumerRid, consumerName, mComponentLogLevel); } } TopologicalPowerComp::Ptr Reader::mapACLineSegment(CIMPP::ACLineSegment *line) { + const auto &lineName = cimString(line->name); + const auto &lineRid = cimString(line->mRID); + SPDLOG_LOGGER_INFO(mSLog, " Found ACLineSegment {} r={} x={} bch={} gch={}", - line->name, (float)line->r.value, (float)line->x.value, + lineName, (float)line->r.value, (float)line->x.value, (float)line->bch.value, (float)line->gch.value); Real resistance = line->r.value; @@ -399,25 +415,25 @@ TopologicalPowerComp::Ptr Reader::mapACLineSegment(CIMPP::ACLineSegment *line) { Matrix cond_3ph = CPS::Math::singlePhaseParameterToThreePhase(conductance); - auto cpsLine = std::make_shared(line->mRID, line->name, + auto cpsLine = std::make_shared(lineRid, lineName, mComponentLogLevel); cpsLine->setParameters(res_3ph, ind_3ph, cap_3ph, cond_3ph); return cpsLine; } else { SPDLOG_LOGGER_INFO(mSLog, " PiLine for EMT not implemented yet"); - auto cpsLine = std::make_shared(line->mRID, line->name, + auto cpsLine = std::make_shared(lineRid, lineName, mComponentLogLevel); cpsLine->setParameters(resistance, inductance, capacitance, conductance); return cpsLine; } } else if (mDomain == Domain::SP) { - auto cpsLine = std::make_shared(line->mRID, line->name, + auto cpsLine = std::make_shared(lineRid, lineName, mComponentLogLevel); cpsLine->setParameters(resistance, inductance, capacitance, conductance); cpsLine->setBaseVoltage(baseVoltage); return cpsLine; } else { - auto cpsLine = std::make_shared(line->mRID, line->name, + auto cpsLine = std::make_shared(lineRid, lineName, mComponentLogLevel); cpsLine->setParameters(resistance, inductance, capacitance, conductance); return cpsLine; @@ -426,14 +442,16 @@ TopologicalPowerComp::Ptr Reader::mapACLineSegment(CIMPP::ACLineSegment *line) { TopologicalPowerComp::Ptr Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { + const auto &transRid = cimString(trans->mRID); if (trans->PowerTransformerEnd.size() != 2) { SPDLOG_LOGGER_WARN( mSLog, "PowerTransformer {} does not have exactly two windings, ignoring", - trans->name); + cimString(trans->name)); return nullptr; } - SPDLOG_LOGGER_INFO(mSLog, "Found PowerTransformer {}", trans->name); + SPDLOG_LOGGER_INFO(mSLog, "Found PowerTransformer {}", + cimString(trans->name)); // assign transformer ends CIMPP::PowerTransformerEnd *end1 = nullptr, *end2 = nullptr; @@ -447,7 +465,8 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { } // setting default values for non-set resistances and reactances - SPDLOG_LOGGER_INFO(mSLog, " PowerTransformerEnd_1 {}", end1->name); + SPDLOG_LOGGER_INFO(mSLog, " PowerTransformerEnd_1 {}", + cimString(end1->name)); SPDLOG_LOGGER_INFO(mSLog, " Srated={} Vrated={}", (float)end1->ratedS.value, (float)end1->ratedU.value); try { @@ -468,7 +487,8 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { "default value of X={}", (float)end1->x.value); } - SPDLOG_LOGGER_INFO(mSLog, " PowerTransformerEnd_2 {}", end2->name); + SPDLOG_LOGGER_INFO(mSLog, " PowerTransformerEnd_2 {}", + cimString(end2->name)); SPDLOG_LOGGER_INFO(mSLog, " Srated={} Vrated={}", (float)end2->ratedS.value, (float)end2->ratedU.value); try { @@ -495,7 +515,7 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { mSLog, " PowerTransformerEnds of {} come with distinct rated power values. " "Using rated power of PowerTransformerEnd_1.", - trans->name); + cimString(trans->name)); } Real ratedPower = unitValue(end1->ratedS.value, UnitMultiplier::M); Real voltageNode1 = unitValue(end1->ratedU.value, UnitMultiplier::k); @@ -554,7 +574,8 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { CPS::Math::singlePhaseParameterToThreePhase(inductance); Bool withResistiveLosses = resistance > 0; auto transformer = std::make_shared( - trans->mRID, trans->name, mComponentLogLevel, withResistiveLosses); + transRid, cimString(trans->name), mComponentLogLevel, + withResistiveLosses); transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs, ratioPhase, resistance_3ph, inductance_3ph); @@ -565,7 +586,7 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { } } else if (mDomain == Domain::SP) { auto transformer = std::make_shared( - trans->mRID, trans->name, mComponentLogLevel); + transRid, cimString(trans->name), mComponentLogLevel); transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs, ratioPhase, resistance, inductance); Real baseVolt = voltageNode1 >= voltageNode2 ? voltageNode1 : voltageNode2; @@ -574,7 +595,8 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { } else { Bool withResistiveLosses = resistance > 0; auto transformer = std::make_shared( - trans->mRID, trans->name, mComponentLogLevel, withResistiveLosses); + transRid, cimString(trans->name), mComponentLogLevel, + withResistiveLosses); transformer->setParameters(voltageNode1, voltageNode2, ratedPower, ratioAbs, ratioPhase, resistance, inductance); return transformer; @@ -583,7 +605,10 @@ Reader::mapPowerTransformer(CIMPP::PowerTransformer *trans) { TopologicalPowerComp::Ptr Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { - SPDLOG_LOGGER_INFO(mSLog, " Found Synchronous machine {}", machine->name); + const auto &machineName = cimString(machine->name); + const auto &machineRid = cimString(machine->mRID); + + SPDLOG_LOGGER_INFO(mSLog, " Found Synchronous machine {}", machineName); if (mDomain == Domain::DP) { SPDLOG_LOGGER_INFO(mSLog, " Create generator in DP domain."); @@ -604,7 +629,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn = dynamic_cast( obj)) { - if (genDyn->SynchronousMachine->mRID == machine->mRID) { + if (cimString(genDyn->SynchronousMachine->mRID) == machineRid) { // stator Real Rs = genDyn->statorResistance.value; Real Ll = genDyn->statorLeakageReactance.value; @@ -634,7 +659,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is TransientStability."); auto gen = DP::Ph1::SynchronGeneratorTrStab::make( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency, Ld_t, H); return gen; @@ -642,7 +667,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator6aOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -651,7 +676,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator6bOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -660,7 +685,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator5OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0); @@ -669,7 +694,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator4OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t); @@ -678,7 +703,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator3OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Td0_t); @@ -687,7 +712,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator4OrderPCM."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t); @@ -696,7 +721,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator4OrderTPM."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t); @@ -705,7 +730,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator6OrderPCM."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -717,7 +742,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { } else if (mGeneratorType == GeneratorType::IdealVoltageSource) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is IdealVoltageSource."); return std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); } else if (mGeneratorType == GeneratorType::None) { throw SystemError("GeneratorType is None. Specify!"); } else { @@ -740,7 +765,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn = dynamic_cast( obj)) { - if (genDyn->SynchronousMachine->mRID == machine->mRID) { + if (cimString(genDyn->SynchronousMachine->mRID) == machineRid) { // stator Real Rs = genDyn->statorResistance.value; Real Ll = genDyn->statorLeakageReactance.value; @@ -770,7 +795,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is TransientStability."); auto gen = SP::Ph1::SynchronGeneratorTrStab::make( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setStandardParametersPU(ratedPower, ratedVoltage, mFrequency, Ld_t, H); return gen; @@ -778,7 +803,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator6aOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -787,7 +812,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator6bOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -796,7 +821,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator5OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0); @@ -805,7 +830,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator4OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t); @@ -814,7 +839,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator3OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Td0_t); @@ -829,7 +854,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { if (CIMPP::GeneratingUnit *genUnit = dynamic_cast(obj)) { for (auto syncGen : genUnit->RotatingMachine) { - if (syncGen->mRID == machine->mRID) { + if (cimString(syncGen->mRID) == machineRid) { // Check whether relevant input data are set, otherwise set default values Real setPointActivePower = 0; Real setPointVoltage = 0; @@ -842,7 +867,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { } catch (ReadingUninitializedField *e) { std::cerr << "Uninitalized setPointActivePower for GeneratingUnit " - << machine->name << ". Using default value of " + << machineName << ". Using default value of " << setPointActivePower << std::endl; } if (machine->RegulatingControl) { @@ -853,7 +878,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { setPointVoltage); } else { std::cerr << "Uninitalized setPointVoltage for GeneratingUnit " - << machine->name << ". Using default value of " + << machineName << ". Using default value of " << setPointVoltage << std::endl; } try { @@ -864,12 +889,12 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { } catch (ReadingUninitializedField *e) { std::cerr << "Uninitalized maximumReactivePower for GeneratingUnit " - << machine->name << ". Using default value of " + << machineName << ". Using default value of " << maximumReactivePower << std::endl; } auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setParameters( unitValue(machine->ratedS.value, UnitMultiplier::M), unitValue(machine->ratedU.value, UnitMultiplier::k), @@ -882,9 +907,9 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { } } SPDLOG_LOGGER_INFO(mSLog, "no corresponding initial power for {}", - machine->name); + machineName); return std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); } else if (mGeneratorType == GeneratorType::None) { throw SystemError("GeneratorType is None. Specify!"); } else { @@ -907,7 +932,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { if (CIMPP::SynchronousMachineTimeConstantReactance *genDyn = dynamic_cast( obj)) { - if (genDyn->SynchronousMachine->mRID == machine->mRID) { + if (cimString(genDyn->SynchronousMachine->mRID) == machineRid) { // stator Real Rs = genDyn->statorResistance.value; @@ -937,7 +962,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { if (mGeneratorType == GeneratorType::FullOrder) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is FullOrder."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setParametersOperationalPerUnit( ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr, Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s, @@ -946,7 +971,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { } else if (mGeneratorType == GeneratorType::FullOrderVBR) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is FullOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setBaseAndOperationalPerUnitParameters( ratedPower, ratedVoltage, mFrequency, poleNum, nomFieldCurr, Rs, Ld, Lq, Ld_t, Lq_t, Ld_s, Lq_s, Ll, Td0_t, Tq0_t, Td0_s, @@ -957,7 +982,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { mSLog, " GeneratorType is SynchronGenerator6aOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -967,7 +992,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { mSLog, " GeneratorType is SynchronGenerator6bOrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s); @@ -976,7 +1001,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator5OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit( ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t, Ld_s, Lq_s, Td0_s, Tq0_s, 0.0); @@ -985,7 +1010,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator4OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Lq_t, Td0_t, Tq0_t); @@ -994,7 +1019,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { SPDLOG_LOGGER_DEBUG( mSLog, " GeneratorType is SynchronGenerator3OrderVBR."); auto gen = std::make_shared( - machine->mRID, machine->name, mComponentLogLevel); + machineRid, machineName, mComponentLogLevel); gen->setOperationalParametersPerUnit(ratedPower, ratedVoltage, mFrequency, H, Ld, Lq, Ll, Ld_t, Td0_t); @@ -1006,12 +1031,12 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { } else if (mGeneratorType == GeneratorType::IdealVoltageSource) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is IdealVoltageSource."); return std::make_shared( - machine->mRID, machine->name, mComponentLogLevel, + machineRid, machineName, mComponentLogLevel, GeneratorType::IdealVoltageSource); } else if (mGeneratorType == GeneratorType::IdealCurrentSource) { SPDLOG_LOGGER_DEBUG(mSLog, " GeneratorType is IdealCurrentSource."); return std::make_shared( - machine->mRID, machine->name, mComponentLogLevel, + machineRid, machineName, mComponentLogLevel, GeneratorType::IdealCurrentSource); } else if (mGeneratorType == GeneratorType::None) { throw SystemError("GeneratorType is None. Specify!"); @@ -1025,7 +1050,7 @@ Reader::mapSynchronousMachine(CIMPP::SynchronousMachine *machine) { TopologicalPowerComp::Ptr Reader::mapExternalNetworkInjection(CIMPP::ExternalNetworkInjection *extnet) { SPDLOG_LOGGER_INFO(mSLog, "Found External Network Injection {}", - extnet->name); + cimString(extnet->name)); Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(extnet); @@ -1083,7 +1108,7 @@ Reader::mapExternalNetworkInjection(CIMPP::ExternalNetworkInjection *extnet) { TopologicalPowerComp::Ptr Reader::mapEquivalentShunt(CIMPP::EquivalentShunt *shunt) { - SPDLOG_LOGGER_INFO(mSLog, "Found shunt {}", shunt->name); + SPDLOG_LOGGER_INFO(mSLog, "Found shunt {}", cimString(shunt->name)); Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(shunt); @@ -1094,6 +1119,137 @@ Reader::mapEquivalentShunt(CIMPP::EquivalentShunt *shunt) { return cpsShunt; } +TopologicalPowerComp::Ptr +Reader::mapDisconnector(CIMPP::Disconnector *disc) { + + // SPDLOG_LOGGER_INFO(mSLog, "Found Disconnector {} with status {}", disc->name, + // (bool)disc->open.value); + + std::cout << disc->open.value << std::endl; + + Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(disc); + Real resistance = 0; + Real inductance = 0; + Real capacitance = 0; + Real conductance = 0; + + Bool status = disc->open.value; + if (status == true){ + + resistance = 1e9; + inductance = 1e9; + capacitance = 10^(-20); + conductance = 10^(-20); + + } else { + + resistance = 10^(-20); + inductance = 10^(-20); + capacitance = 1e9; + conductance = 1e9; + + } + + + if (mDomain == Domain::EMT) { + if (mPhase == PhaseType::ABC) { + Matrix res_3ph = CPS::Math::singlePhaseParameterToThreePhase(resistance); + Matrix ind_3ph = CPS::Math::singlePhaseParameterToThreePhase(inductance); + Matrix cap_3ph = CPS::Math::singlePhaseParameterToThreePhase(capacitance); + Matrix cond_3ph = + CPS::Math::singlePhaseParameterToThreePhase(conductance); + + auto cpsLine = std::make_shared(disc->mRID, disc->name, + mComponentLogLevel); + cpsLine->setParameters(res_3ph, ind_3ph, cap_3ph, cond_3ph); + return cpsLine; + } else { + SPDLOG_LOGGER_INFO(mSLog, " PiLine for EMT not implemented yet"); + auto cpsLine = std::make_shared(disc->mRID, disc->name, + mComponentLogLevel); + cpsLine->setParameters(resistance, inductance, capacitance, conductance); + return cpsLine; + } + } else if (mDomain == Domain::SP) { + auto cpsLine = std::make_shared(disc->mRID, disc->name, + mComponentLogLevel); + cpsLine->setParameters(resistance, inductance, capacitance, conductance); + cpsLine->setBaseVoltage(baseVoltage); + return cpsLine; + } else { + auto cpsLine = std::make_shared(disc->mRID, disc->name, + mComponentLogLevel); + cpsLine->setParameters(resistance, inductance, capacitance, conductance); + return cpsLine; + } +} + +TopologicalPowerComp::Ptr +Reader::mapBreaker(CIMPP::Breaker *cb) { + // SPDLOG_LOGGER_INFO(mSLog, + // "Found Breaker {} with status {}", + // cb->name, + // (bool)cb->open.value); + + Real baseVoltage = determineBaseVoltageAssociatedWithEquipment(cb); + + Real resistance = 0; + Real inductance = 0; + Real capacitance = 0; + Real conductance = 0; + + Bool status = cb->open.value; + + if (status == true){ + + resistance = 1e9; + inductance = 1e9; + capacitance = 10^(-10); + conductance = 10^(-10); + + } else { + + resistance = 10^(-10); + inductance = 10^(-10); + capacitance = 1e9; + conductance = 1e9; + + } + + if (mDomain == Domain::EMT) { + if (mPhase == PhaseType::ABC) { + Matrix res_3ph = CPS::Math::singlePhaseParameterToThreePhase(resistance); + Matrix ind_3ph = CPS::Math::singlePhaseParameterToThreePhase(inductance); + Matrix cap_3ph = CPS::Math::singlePhaseParameterToThreePhase(capacitance); + Matrix cond_3ph = + CPS::Math::singlePhaseParameterToThreePhase(conductance); + + auto cpsLine = std::make_shared(cb->mRID, cb->name, + mComponentLogLevel); + cpsLine->setParameters(res_3ph, ind_3ph, cap_3ph, cond_3ph); + return cpsLine; + } else { + // SPDLOG_LOGGER_INFO(mSLog, " PiLine for EMT not implemented yet"); + auto cpsLine = std::make_shared(cb->mRID, cb->name, + mComponentLogLevel); + cpsLine->setParameters(resistance, inductance, capacitance, conductance); + return cpsLine; + } + } else if (mDomain == Domain::SP) { + auto cpsLine = std::make_shared(cb->mRID, cb->name, + mComponentLogLevel); + cpsLine->setParameters(resistance, inductance, capacitance, conductance); + cpsLine->setBaseVoltage(baseVoltage); + return cpsLine; + } else { + auto cpsLine = std::make_shared(cb->mRID, cb->name, + mComponentLogLevel); + cpsLine->setParameters(resistance, inductance, capacitance, conductance); + return cpsLine; + } + +} + Real Reader::determineBaseVoltageAssociatedWithEquipment( CIMPP::ConductingEquipment *equipment) { Real baseVoltage = 0; @@ -1103,7 +1259,7 @@ Real Reader::determineBaseVoltageAssociatedWithEquipment( if (CIMPP::BaseVoltage *baseVolt = dynamic_cast(obj)) { for (auto comp : baseVolt->ConductingEquipment) { - if (comp->name == equipment->name) { + if (cimString(comp->name) == cimString(equipment->name)) { baseVoltage = unitValue(baseVolt->nominalVoltage.value, UnitMultiplier::k); } @@ -1116,7 +1272,8 @@ Real Reader::determineBaseVoltageAssociatedWithEquipment( if (CIMPP::TopologicalNode *topNode = dynamic_cast(obj)) { for (auto term : topNode->Terminal) { - if (term->ConductingEquipment->name == equipment->name) { + if (cimString(term->ConductingEquipment->name) == + cimString(equipment->name)) { baseVoltage = unitValue(topNode->BaseVoltage->nominalVoltage.value, UnitMultiplier::k); } @@ -1132,78 +1289,79 @@ template void Reader::processTopologicalNode(CIMPP::TopologicalNode *topNode) { // Add this node to global node list and assign simulation node incrementally. int matrixNodeIndex = Int(mPowerflowNodes.size()); - mPowerflowNodes[topNode->mRID] = SimNode::make( - topNode->mRID, topNode->name, matrixNodeIndex, mPhase); + const auto &nodeRid = cimString(topNode->mRID); + mPowerflowNodes[nodeRid] = SimNode::make( + nodeRid, cimString(topNode->name), matrixNodeIndex, mPhase); if (mPhase == PhaseType::ABC) { SPDLOG_LOGGER_INFO( - mSLog, "TopologicalNode {} phase A as simulation node {} ", - topNode->mRID, - mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::A)); + mSLog, "TopologicalNode {} phase A as simulation node {} ", nodeRid, + mPowerflowNodes[nodeRid]->matrixNodeIndex(PhaseType::A)); SPDLOG_LOGGER_INFO( - mSLog, "TopologicalNode {} phase B as simulation node {}", - topNode->mRID, - mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::B)); + mSLog, "TopologicalNode {} phase B as simulation node {}", nodeRid, + mPowerflowNodes[nodeRid]->matrixNodeIndex(PhaseType::B)); SPDLOG_LOGGER_INFO( - mSLog, "TopologicalNode {} phase C as simulation node {}", - topNode->mRID, - mPowerflowNodes[topNode->mRID]->matrixNodeIndex(PhaseType::C)); + mSLog, "TopologicalNode {} phase C as simulation node {}", nodeRid, + mPowerflowNodes[nodeRid]->matrixNodeIndex(PhaseType::C)); } else SPDLOG_LOGGER_INFO(mSLog, "TopologicalNode id: {}, name: {} as simulation node {}", - topNode->mRID, topNode->name, - mPowerflowNodes[topNode->mRID]->matrixNodeIndex()); + nodeRid, cimString(topNode->name), + mPowerflowNodes[nodeRid]->matrixNodeIndex()); for (auto term : topNode->Terminal) { // Insert Terminal if it does not exist in the map and add reference to node. // This could be optimized because the Terminal is searched twice. - auto cpsTerm = SimTerminal::make(term->mRID); - mPowerflowTerminals.insert(std::make_pair(term->mRID, cpsTerm)); - cpsTerm->setNode(std::dynamic_pointer_cast>( - mPowerflowNodes[topNode->mRID])); + const auto &termRid = cimString(term->mRID); + auto cpsTerm = SimTerminal::make(termRid); + mPowerflowTerminals.insert(std::make_pair(termRid, cpsTerm)); + cpsTerm->setNode( + std::dynamic_pointer_cast>(mPowerflowNodes[nodeRid])); if (!term->sequenceNumber.initialized) term->sequenceNumber = 1; - SPDLOG_LOGGER_INFO(mSLog, " Terminal {}, sequenceNumber {}", term->mRID, + SPDLOG_LOGGER_INFO(mSLog, " Terminal {}, sequenceNumber {}", termRid, (int)term->sequenceNumber); // Try to process Equipment connected to Terminal. CIMPP::ConductingEquipment *equipment = term->ConductingEquipment; if (!equipment) { SPDLOG_LOGGER_WARN(mSLog, "Terminal {} has no Equipment, ignoring!", - term->mRID); + termRid); } else { // Insert Equipment if it does not exist in the map and add reference to Terminal. // This could be optimized because the Equipment is searched twice. - if (mPowerflowEquipment.find(equipment->mRID) == - mPowerflowEquipment.end()) { + const auto &equipmentRid = cimString(equipment->mRID); + if (mPowerflowEquipment.find(equipmentRid) == mPowerflowEquipment.end()) { TopologicalPowerComp::Ptr comp = mapComponent(equipment); if (comp) { - mPowerflowEquipment.insert(std::make_pair(equipment->mRID, comp)); + mPowerflowEquipment.insert(std::make_pair(equipmentRid, comp)); } else { - SPDLOG_LOGGER_WARN(mSLog, "Could not map equipment {}", - equipment->mRID); + SPDLOG_LOGGER_WARN(mSLog, "Could not map equipment {}", equipmentRid); continue; } } - auto pfEquipment = mPowerflowEquipment.at(equipment->mRID); + auto pfEquipment = mPowerflowEquipment.at(equipmentRid); if (pfEquipment == nullptr) { - SPDLOG_LOGGER_ERROR(mSLog, "Equipment {} is null in equipment list", equipment->mRID); + SPDLOG_LOGGER_ERROR(mSLog, "Equipment {} is null in equipment list", + equipmentRid); throw SystemError("Equipment is null in equipment list."); } std::dynamic_pointer_cast>(pfEquipment) ->setTerminalAt(std::dynamic_pointer_cast>( - mPowerflowTerminals[term->mRID]), + mPowerflowTerminals[termRid]), term->sequenceNumber - 1); SPDLOG_LOGGER_INFO(mSLog, " Added Terminal {} to Equipment {}", - term->mRID, equipment->mRID); + termRid, equipmentRid); } } } + + template void Reader::processTopologicalNode(CIMPP::TopologicalNode *topNode); template void diff --git a/dpsim-models/src/CMakeLists.txt b/dpsim-models/src/CMakeLists.txt index ff0b7ddd75..9eed2cc23b 100644 --- a/dpsim-models/src/CMakeLists.txt +++ b/dpsim-models/src/CMakeLists.txt @@ -54,6 +54,7 @@ list(APPEND MODELS_SOURCES DP/DP_Ph3_Capacitor.cpp DP/DP_Ph3_Inductor.cpp DP/DP_Ph3_Resistor.cpp + DP/DP_Ph3_PiLine.cpp DP/DP_Ph3_SeriesResistor.cpp DP/DP_Ph3_SeriesSwitch.cpp DP/DP_Ph3_SynchronGeneratorDQ.cpp @@ -69,7 +70,11 @@ list(APPEND MODELS_SOURCES EMT/EMT_Ph1_VoltageSource.cpp EMT/EMT_Ph1_VoltageSourceRamp.cpp EMT/EMT_Ph1_VoltageSourceNorton.cpp + EMT/EMT_Ph1_PiLine.cpp EMT/EMT_Ph1_Switch.cpp + EMT/EMT_Ph1_SSN_Full_Serial_RLC.cpp + EMT/EMT_Ph1_SSNTypeI2T.cpp + EMT/EMT_Ph1_SSNTypeV2T.cpp EMT/EMT_Ph3_CurrentSource.cpp EMT/EMT_Ph3_VoltageSource.cpp @@ -142,6 +147,7 @@ list(APPEND MODELS_SOURCES Signal/DecouplingLine.cpp Signal/DecouplingLineEMT.cpp + Signal/DecouplingLineEMT_Ph3.cpp Signal/Exciter.cpp Signal/FIRFilter.cpp Signal/TurbineGovernor.cpp @@ -158,13 +164,11 @@ list(APPEND MODELS_SOURCES if(WITH_CIM) list(APPEND MODELS_SOURCES CIM/Reader.cpp) - - list(APPEND MODELS_LIBRARIES libcimpp) + list(APPEND MODELS_LIBRARIES CIMPP::cimpp) endif() if(WITH_GRAPHVIZ) list(APPEND MODELS_SOURCES Graph.cpp) - list(APPEND MODELS_INCLUDE_DIRS ${GRAPHVIZ_INCLUDE_DIRS}) list(APPEND MODELS_LIBRARIES ${GRAPHVIZ_LIBRARIES}) endif() diff --git a/dpsim-models/src/CSVReader.cpp b/dpsim-models/src/CSVReader.cpp index f31f4ca0bc..32ef715a49 100644 --- a/dpsim-models/src/CSVReader.cpp +++ b/dpsim-models/src/CSVReader.cpp @@ -139,24 +139,21 @@ std::vector CSVReader::readLoadProfileDP(fs::path file, Real start_time, std::ifstream csvfile(file); CSVReaderIterator row_(csvfile); - // ignore the first row if it is a title + // Ignore the first row if it is a title if (mSkipFirstRow && !std::isdigit((*row_).get(0)[0])) { row_.next(); } - /* - loop over rows of the csv file to find the entry point to read in. - if start_time and end_time are negative (as default), it reads in all rows. - */ + /* Loop over rows of the csv file to find the entry point to read in. + * if start_time and end_time are negative (as default), it reads in all rows. + */ Real presentTime = 0; for (; row_ != CSVReaderIterator(); row_.next()) { if ((start_time < 0) | (Int(presentTime) + 1 > Int(start_time))) break; presentTime++; } - /* - reading data after entry point until end_time is reached - */ + // Reading data after entry point until end_time is reached. for (; row_ != CSVReaderIterator(); row_.next()) { // IMPORTANT: take care of units. assume kW PQData pq; @@ -166,197 +163,12 @@ std::vector CSVReader::readLoadProfileDP(fs::path file, Real start_time, load_profileDP.push_back(pq); if (end_time > 0 && presentTime > end_time) break; - /*while (presentTime + time_step < Int(presentTime) + 1) - { - presentTime += time_step; - p_data.push_back(p_data.back()); - }*/ presentTime = Int(presentTime) + 1; } std::cout << "CSV loaded." << std::endl; return load_profileDP; } -// void CSVReader::assignLoadProfileSP(std::vector>& loads, -// Real start_time, Real time_step, Real end_time, Real scale_factor, -// CSVReader::Mode mode, CSVReader::DataFormat format) { - -// switch (mode) { -// case CSVReader::Mode::AUTO: { -// for (auto load : loads) { -// if(!load->isLoad()) -// continue; -// String load_name = load->name(); -// for (auto file : mFileList) { -// String file_name = file.filename().string(); -// /// changing file name and load name to upper case for later matching -// for (auto & c : load_name) c = toupper(c); -// for (auto & c : file_name) c = toupper(c); -// /// strip off all non-alphanumeric characters -// load_name.erase(remove_if(load_name.begin(), load_name.end(), [](char c) { return !isalnum(c); }), load_name.end()); -// file_name.erase(remove_if(file_name.begin(), file_name.end(), [](char c) { return !isalnum(c); }), file_name.end()); -// if (std::stoi(file_name) == std::stoi(load_name)) { -// load->mLoadProfile = readLoadProfileDP(file, start_time, time_step, end_time, scale_factor, format); -// SPDLOG_LOGGER_INFO(mSLog, "Assigned {} to {}", file.filename().string(), load->name()); -// } -// } -// } - -// break; -// } -// case CSVReader::Mode::MANUAL: { -// Int LP_assigned_counter = 0; -// Int LP_not_assigned_counter = 0; -// SPDLOG_LOGGER_INFO(mSLog, "Assigning load profiles with user defined pattern ..."); -// for (auto load : loads) { -// std::map::iterator file = mAssignPattern.find(load->name()); -// if (file == mAssignPattern.end()) { - -// SPDLOG_LOGGER_INFO(mSLog, "{} has no profile given.", load->name()); -// LP_not_assigned_counter++; -// continue; -// } -// for(auto path: mFileList){ -// if(path.string().find(file->second)!= std::string::npos){ -// load->mLoadProfile = readLoadProfileDP(path, start_time, time_step, end_time, scale_factor); -// SPDLOG_LOGGER_INFO(mSLog, "Assigned {}.csv to {}", file->second, load->name()); -// LP_assigned_counter++; -// } - -// } -// } -// SPDLOG_LOGGER_INFO(mSLog, "Assigned profiles for {} loads, {} not assigned.", LP_assigned_counter, LP_not_assigned_counter); -// break; -// } -// default: { -// throw std::invalid_argument( -// "Load profile assign mode error"); -// break; -// } -// } -// } - -// void CSVReader::assignLoadProfilePF(std::vector>& loads, -// Real start_time, Real time_step, Real end_time, Real scale_factor, -// CSVReader::Mode mode, CSVReader::DataFormat format) { - -// switch (mode) { -// case CSVReader::Mode::AUTO: { -// for (auto load : loads) { -// if(!load->isLoad()) -// continue; -// String load_name = load->name(); -// for (auto file : mFileList) { -// String file_name = file.filename().string(); -// /// changing file name and load name to upper case for later matching -// for (auto & c : load_name) c = toupper(c); -// for (auto & c : file_name) c = toupper(c); -// /// strip off all non-alphanumeric characters -// load_name.erase(remove_if(load_name.begin(), load_name.end(), [](char c) { return !isalnum(c); }), load_name.end()); -// file_name.erase(remove_if(file_name.begin(), file_name.end(), [](char c) { return !isalnum(c); }), file_name.end()); -// if (std::stoi(file_name) == std::stoi(load_name)) { -// load->mPFAvVoltageSourceInverter->mLoadProfile = readLoadProfile(fs::path(mPath + file->second + ".csv"), start_time, time_step, end_time); -// load->mPFAvVoltageSourceInverter->use_profile = true; -// SPDLOG_LOGGER_INFO(mSLog, "Assigned {} to {}", file.filename().string(), load->name()); -// } -// } -// } - -// break; -// } -// case CSVReader::Mode::MANUAL: { -// Int LP_assigned_counter = 0; -// Int LP_not_assigned_counter = 0; -// SPDLOG_LOGGER_INFO(mSLog, "Assigning load profiles with user defined pattern ..."); -// for (auto load : loads) { -// std::map::iterator file = mAssignPattern.find(load->name()); -// if (file == mAssignPattern.end()) { - -// SPDLOG_LOGGER_INFO(mSLog, "{} has no profile given.", load->name()); -// LP_not_assigned_counter++; -// continue; -// } -// for(auto path: mFileList){ -// if(path.string().find(file->second)!= std::string::npos){ -// load->mPFAvVoltageSourceInverter->mLoadProfile = readLoadProfile(fs::path(mPath + file->second + ".csv"), start_time, time_step, end_time); -// load->mPFAvVoltageSourceInverter->use_profile = true; -// SPDLOG_LOGGER_INFO(mSLog, "Assigned {}.csv to {}", file->second, load->name()); -// LP_assigned_counter++; -// } - -// } -// } -// SPDLOG_LOGGER_INFO(mSLog, "Assigned profiles for {} loads, {} not assigned.", LP_assigned_counter, LP_not_assigned_counter); -// break; -// } -// default: { -// throw std::invalid_argument( -// "Load profile assign mode error"); -// break; -// } -// } -// } - -// TODO: profile handling currently not supported by average inverter in DP1ph -// void CSVReader::assignLoadProfileDP(std::vector>& loads, -// Real start_time, Real time_step, Real end_time, Real scale_factor, -// CSVReader::Mode mode, CSVReader::DataFormat format) { - -// switch (mode) { -// case CSVReader::Mode::AUTO: { -// for (auto load : loads) { -// if(!load->isLoad()) -// continue; -// String load_name = load->name(); -// for (auto file : mFileList) { -// String file_name = file.filename().string(); -// /// changing file name and load name to upper case for later matching -// for (auto & c : load_name) c = toupper(c); -// for (auto & c : file_name) c = toupper(c); -// /// strip off all non-alphanumeric characters -// load_name.erase(remove_if(load_name.begin(), load_name.end(), [](char c) { return !isalnum(c); }), load_name.end()); -// file_name.erase(remove_if(file_name.begin(), file_name.end(), [](char c) { return !isalnum(c); }), file_name.end()); -// if (std::stoi(file_name) == std::stoi(load_name)) { -// load->mLoadProfile = readLoadProfileDP(file, start_time, time_step, end_time, scale_factor, format); -// SPDLOG_LOGGER_INFO(mSLog, "Assigned {} to {}", file.filename().string(), load->name()); -// } -// } -// } - -// break; -// } -// case CSVReader::Mode::MANUAL: { -// Int LP_assigned_counter = 0; -// Int LP_not_assigned_counter = 0; -// SPDLOG_LOGGER_INFO(mSLog, "Assigning load profiles with user defined pattern ..."); -// for (auto load : loads) { -// std::map::iterator file = mAssignPattern.find(load->name()); -// if (file == mAssignPattern.end()) { - -// SPDLOG_LOGGER_INFO(mSLog, "{} has no profile given.", load->name()); -// LP_not_assigned_counter++; -// continue; -// } -// for(auto path: mFileList){ -// if(path.string().find(file->second)!= std::string::npos){ -// load->mLoadProfile = readLoadProfileDP(path, start_time, time_step, end_time, scale_factor); -// SPDLOG_LOGGER_INFO(mSLog, "Assigned {}.csv to {}", file->second, load->name()); -// LP_assigned_counter++; -// } - -// } -// } -// SPDLOG_LOGGER_INFO(mSLog, "Assigned profiles for {} loads, {} not assigned.", LP_assigned_counter, LP_not_assigned_counter); -// break; -// } -// default: { -// throw std::invalid_argument( -// "Load profile assign mode error"); -// break; -// } -// } -// } - PowerProfile CSVReader::readLoadProfile(fs::path file, Real start_time, Real time_step, Real end_time, CSVReader::DataFormat format) { @@ -374,10 +186,10 @@ PowerProfile CSVReader::readLoadProfile(fs::path file, Real start_time, } /* - loop over rows of the csv file to find the entry point to read in. - and determine data type prior to read in. (assuming only time,p,q or time,weighting factor) - if start_time and end_time are negative (as default), it reads in all rows. - */ + loop over rows of the csv file to find the entry point to read in. + and determine data type prior to read in. (assuming only time,p,q or time,weighting factor) + if start_time and end_time are negative (as default), it reads in all rows. + */ for (; loop != CSVReaderIterator(); loop.next()) { CSVReaderIterator nextRow = loop; nextRow.next(); @@ -392,8 +204,8 @@ PowerProfile CSVReader::readLoadProfile(fs::path file, Real start_time, } } /* - reading data after entry point until end_time is reached - */ + reading data after entry point until end_time is reached + */ for (; loop != CSVReaderIterator(); loop.next()) { CPS::Real currentTime = (need_that_conversion) ? time_format_convert((*loop).get(0)) @@ -448,28 +260,21 @@ std::vector CSVReader::readPQData(fs::path file, Real start_time, } /* - loop over rows of the csv file to find the entry point to read in. - if start_time and end_time are negative (as default), it reads in all rows. - */ + loop over rows of the csv file to find the entry point to read in. + if start_time and end_time are negative (as default), it reads in all rows. + */ Real presentTime = 0; for (; row_ != CSVReaderIterator(); row_.next()) { if ((start_time < 0) | (Int(presentTime) + 1 > Int(start_time))) break; presentTime++; } - /* - reading data after entry point until end_time is reached - */ + // Reading data after entry point until end_time is reached. for (; row_ != CSVReaderIterator(); row_.next()) { // IMPORTANT: take care of units. assume kW p_data.push_back(std::stod((*row_).get(0)) * 1000); if (end_time > 0 && presentTime > end_time) break; - /*while (presentTime + time_step < Int(presentTime) + 1) - { - presentTime += time_step; - p_data.push_back(p_data.back()); - }*/ presentTime = Int(presentTime) + 1; } std::cout << "CSV loaded." << std::endl; @@ -491,12 +296,12 @@ void CSVReader::assignLoadProfile(CPS::SystemTopology &sys, Real start_time, String load_name = load->name(); for (auto file : mFileList) { String file_name = file.filename().string(); - /// changing file name and load name to upper case for later matching + // Changing file name and load name to upper case for later matching for (auto &c : load_name) c = toupper(c); for (auto &c : file_name) c = toupper(c); - /// strip off all non-alphanumeric characters + // Strip off all non-alphanumeric characters load_name.erase(remove_if(load_name.begin(), load_name.end(), [](char c) { return !isalnum(c); }), load_name.end()); diff --git a/dpsim-models/src/DP/DP_Ph1_NetworkInjection.cpp b/dpsim-models/src/DP/DP_Ph1_NetworkInjection.cpp index ccd16a84e7..6413b9d8f4 100644 --- a/dpsim-models/src/DP/DP_Ph1_NetworkInjection.cpp +++ b/dpsim-models/src/DP/DP_Ph1_NetworkInjection.cpp @@ -159,17 +159,17 @@ void DP::Ph1::NetworkInjection::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ + /* New state vector definintion: + * state[0]=node0_voltage + * state[1]=node1_voltage + * .... + * state[n]=noden_voltage + * state[n+1]=component0_voltage + * state[n+2]=component0_inductance (not yet implemented) + * ... + * state[m-1]=componentm_voltage + * state[m]=componentm_inductance + */ int Pos1 = matrixNodeIndex(0); int Pos2 = matrixNodeIndex(1); diff --git a/dpsim-models/src/DP/DP_Ph1_PiLine.cpp b/dpsim-models/src/DP/DP_Ph1_PiLine.cpp index 81d08e4013..00fbe59adf 100644 --- a/dpsim-models/src/DP/DP_Ph1_PiLine.cpp +++ b/dpsim-models/src/DP/DP_Ph1_PiLine.cpp @@ -1,10 +1,7 @@ -/* Copyright 2017-2021 Institute for Automation of Complex Power Systems, - * EONERC, RWTH Aachen University - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - *********************************************************************************/ +/* Author: Christoph Wirtz + * SPDX-FileCopyrightText: 2025 FGH e.V. + * SPDX-License-Identifier: MPL-2.0 + */ #include @@ -179,6 +176,7 @@ void DP::Ph1::PiLine::mnaCompUpdateCurrent(const Matrix &leftVector) { (**mIntfCurrent)(0, 0) = mSubSeriesInductor->intfCurrent()(0, 0); } +// #### Tear Methods #### MNAInterface::List DP::Ph1::PiLine::mnaTearGroundComponents() { MNAInterface::List gndComponents; @@ -212,4 +210,5 @@ void DP::Ph1::PiLine::mnaTearApplyVoltageStamp(Matrix &voltageVector) { void DP::Ph1::PiLine::mnaTearPostStep(Complex voltage, Complex current) { mSubSeriesInductor->mnaTearPostStep(voltage - current * **mSeriesRes, current); + (**mIntfCurrent)(0, 0) = mSubSeriesInductor->intfCurrent()(0, 0); } diff --git a/dpsim-models/src/DP/DP_Ph1_ProfileVoltageSource.cpp b/dpsim-models/src/DP/DP_Ph1_ProfileVoltageSource.cpp index 458105656c..0918852ae0 100644 --- a/dpsim-models/src/DP/DP_Ph1_ProfileVoltageSource.cpp +++ b/dpsim-models/src/DP/DP_Ph1_ProfileVoltageSource.cpp @@ -17,8 +17,12 @@ using namespace CPS; -DP::Ph1::ProfileVoltageSource::ProfileVoltageSource(String uid, String name, std::filesystem::path sourceFile, Logger::Level logLevel) - : MNASimPowerComp(uid, name, true, true, logLevel), mVoltage(mAttributes->createDynamic("V")), mSourceFile(sourceFile), mSourceIndex(0), mSamples() { +DP::Ph1::ProfileVoltageSource::ProfileVoltageSource( + String uid, String name, std::filesystem::path sourceFile, + Logger::Level logLevel) + : MNASimPowerComp(uid, name, true, true, logLevel), + mVoltage(mAttributes->createDynamic("V")), + mSourceFile(sourceFile), mSourceIndex(0), mSamples() { setVirtualNodeNumber(1); setTerminalNumber(2); **mIntfVoltage = MatrixComp::Zero(1, 1); @@ -32,53 +36,65 @@ void DP::Ph1::ProfileVoltageSource::readFromFile() { std::ifstream file(mSourceFile, std::ios::binary | std::ios::ate); if (!file.is_open()) { - throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not open file " + mSourceFile.string()); + throw SystemError( + "ProfileVoltageSource::ProfileVoltageSource could not open file " + + mSourceFile.string()); } std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); - size_t sample_num = size / (sizeof(struct villas::node::Sample) + SAMPLE_DATA_LENGTH(1)); + size_t sample_num = + size / (sizeof(struct villas::node::Sample) + SAMPLE_DATA_LENGTH(1)); std::vector buffer(size); if (!file.read(buffer.data(), size)) { - throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not read file " + mSourceFile.string()); + throw SystemError( + "ProfileVoltageSource::ProfileVoltageSource could not read file " + + mSourceFile.string()); } unsigned i, j; Villas__Node__Message *pb_msg; - pb_msg = villas__node__message__unpack(nullptr, size, (uint8_t *)buffer.data()); + pb_msg = + villas__node__message__unpack(nullptr, size, (uint8_t *)buffer.data()); if (!pb_msg) - throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not unpack Protobuf message"); + throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not " + "unpack Protobuf message"); for (i = 0; i < pb_msg->n_samples; i++) { Villas__Node__Sample *pb_smp = pb_msg->samples[i]; if (pb_smp->type != VILLAS__NODE__SAMPLE__TYPE__DATA) - throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not unpack Protobuf message"); + throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not " + "unpack Protobuf message"); if (pb_smp->n_values != 1) { - throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not unpack Protobuf message"); + throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not " + "unpack Protobuf message"); } for (j = 0; j < pb_smp->n_values; j++) { Villas__Node__Value *pb_val = pb_smp->values[j]; if (pb_val->value_case != VILLAS__NODE__VALUE__VALUE_F) - throw SystemError("ProfileVoltageSource::ProfileVoltageSource could not unpack Protobuf message"); + throw SystemError("ProfileVoltageSource::ProfileVoltageSource could " + "not unpack Protobuf message"); mSamples.push_back(pb_val->f); } } villas__node__message__free_unpacked(pb_msg, nullptr); - std::cout << "Read " << mSamples.size() << " samples from file " << mSourceFile << std::endl; + std::cout << "Read " << mSamples.size() << " samples from file " + << mSourceFile << std::endl; for (double sample : mSamples) { std::cout << sample << std::endl; } } -void DP::Ph1::ProfileVoltageSource::setSourceFile(std::filesystem::path file, size_t index) { +void DP::Ph1::ProfileVoltageSource::setSourceFile(std::filesystem::path file, + size_t index) { mSourceFile = file; mSourceIndex = index; readFromFile(); @@ -90,7 +106,8 @@ SimPowerComp::Ptr DP::Ph1::ProfileVoltageSource::clone(String name) { return copy; } -void DP::Ph1::ProfileVoltageSource::initializeFromNodesAndTerminals(Real frequency) { +void DP::Ph1::ProfileVoltageSource::initializeFromNodesAndTerminals( + Real frequency) { /// CHECK: The frequency parameter is unused if (**mVoltage == Complex(0, 0)) **mVoltage = initialSingleVoltage(1) - initialSingleVoltage(0); @@ -98,19 +115,26 @@ void DP::Ph1::ProfileVoltageSource::initializeFromNodesAndTerminals(Real frequen // #### MNA functions #### -void DP::Ph1::ProfileVoltageSource::mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) { +void DP::Ph1::ProfileVoltageSource::mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { attributeDependencies.push_back(mVoltage); modifiedAttributes.push_back(mRightVector); modifiedAttributes.push_back(mIntfVoltage); } -void DP::Ph1::ProfileVoltageSource::mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector) { +void DP::Ph1::ProfileVoltageSource::mnaCompAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { attributeDependencies.push_back(leftVector); modifiedAttributes.push_back(mIntfCurrent); }; -void DP::Ph1::ProfileVoltageSource::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { +void DP::Ph1::ProfileVoltageSource::mnaCompInitialize( + Real omega, Real timeStep, Attribute::Ptr leftVector) { updateMatrixNodeIndices(); (**mIntfVoltage)(0, 0) = *mVoltage; @@ -120,10 +144,13 @@ void DP::Ph1::ProfileVoltageSource::mnaCompInitialize(Real omega, Real timeStep, "\nInitial voltage {:s}" "\nInitial current {:s}" "\n--- MNA initialization finished ---", - Logger::phasorToString((**mIntfVoltage)(0, 0)), Logger::phasorToString((**mIntfCurrent)(0, 0))); + Logger::phasorToString((**mIntfVoltage)(0, 0)), + Logger::phasorToString((**mIntfCurrent)(0, 0))); } -void DP::Ph1::ProfileVoltageSource::mnaCompInitializeHarm(Real omega, Real timeStep, std::vector::Ptr> leftVectors) { +void DP::Ph1::ProfileVoltageSource::mnaCompInitializeHarm( + Real omega, Real timeStep, + std::vector::Ptr> leftVectors) { updateMatrixNodeIndices(); (**mIntfVoltage)(0, 0) = *mVoltage; @@ -133,61 +160,95 @@ void DP::Ph1::ProfileVoltageSource::mnaCompInitializeHarm(Real omega, Real timeS **mRightVector = Matrix::Zero(leftVectors[0]->get().rows(), mNumFreqs); } -void DP::Ph1::ProfileVoltageSource::mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) { +void DP::Ph1::ProfileVoltageSource::mnaCompApplySystemMatrixStamp( + SparseMatrixRow &systemMatrix) { for (UInt freq = 0; freq < mNumFreqs; freq++) { if (terminalNotGrounded(0)) { - Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(0), Complex(-1, 0), mNumFreqs, freq); - Math::setMatrixElement(systemMatrix, matrixNodeIndex(0), mVirtualNodes[0]->matrixNodeIndex(), Complex(-1, 0), mNumFreqs, freq); + Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(0), Complex(-1, 0), mNumFreqs, + freq); + Math::setMatrixElement(systemMatrix, matrixNodeIndex(0), + mVirtualNodes[0]->matrixNodeIndex(), + Complex(-1, 0), mNumFreqs, freq); } if (terminalNotGrounded(1)) { - Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(1), Complex(1, 0), mNumFreqs, freq); - Math::setMatrixElement(systemMatrix, matrixNodeIndex(1), mVirtualNodes[0]->matrixNodeIndex(), Complex(1, 0), mNumFreqs, freq); + Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(1), Complex(1, 0), mNumFreqs, + freq); + Math::setMatrixElement(systemMatrix, matrixNodeIndex(1), + mVirtualNodes[0]->matrixNodeIndex(), Complex(1, 0), + mNumFreqs, freq); } SPDLOG_LOGGER_INFO(mSLog, "-- Stamp frequency {:d} ---", freq); if (terminalNotGrounded(0)) { - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., matrixNodeIndex(0), mVirtualNodes[0]->matrixNodeIndex()); - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(0)); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., + matrixNodeIndex(0), + mVirtualNodes[0]->matrixNodeIndex()); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., + mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(0)); } if (terminalNotGrounded(1)) { - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(1)); - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., matrixNodeIndex(1), mVirtualNodes[0]->matrixNodeIndex()); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., + mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(1)); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., + matrixNodeIndex(1), + mVirtualNodes[0]->matrixNodeIndex()); } } } -void DP::Ph1::ProfileVoltageSource::mnaCompApplySystemMatrixStampHarm(SparseMatrixRow &systemMatrix, Int freqIdx) { +void DP::Ph1::ProfileVoltageSource::mnaCompApplySystemMatrixStampHarm( + SparseMatrixRow &systemMatrix, Int freqIdx) { if (terminalNotGrounded(0)) { - Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(0), Complex(-1, 0)); - Math::setMatrixElement(systemMatrix, matrixNodeIndex(0), mVirtualNodes[0]->matrixNodeIndex(), Complex(-1, 0)); + Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(0), Complex(-1, 0)); + Math::setMatrixElement(systemMatrix, matrixNodeIndex(0), + mVirtualNodes[0]->matrixNodeIndex(), Complex(-1, 0)); } if (terminalNotGrounded(1)) { - Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(1), Complex(1, 0)); - Math::setMatrixElement(systemMatrix, matrixNodeIndex(1), mVirtualNodes[0]->matrixNodeIndex(), Complex(1, 0)); + Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(1), Complex(1, 0)); + Math::setMatrixElement(systemMatrix, matrixNodeIndex(1), + mVirtualNodes[0]->matrixNodeIndex(), Complex(1, 0)); } SPDLOG_LOGGER_INFO(mSLog, "-- Stamp frequency {:d} ---", freqIdx); if (terminalNotGrounded(0)) { - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., matrixNodeIndex(0), mVirtualNodes[0]->matrixNodeIndex()); - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(0)); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., + matrixNodeIndex(0), mVirtualNodes[0]->matrixNodeIndex()); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", -1., + mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(0)); } if (terminalNotGrounded(1)) { - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(1)); - SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., matrixNodeIndex(1), mVirtualNodes[0]->matrixNodeIndex()); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., + mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(1)); + SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1., + matrixNodeIndex(1), mVirtualNodes[0]->matrixNodeIndex()); } } -void DP::Ph1::ProfileVoltageSource::mnaCompApplyRightSideVectorStamp(Matrix &rightVector) { +void DP::Ph1::ProfileVoltageSource::mnaCompApplyRightSideVectorStamp( + Matrix &rightVector) { // TODO: Is this correct with two nodes not gnd? - Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(), (**mIntfVoltage)(0, 0), mNumFreqs); - SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}", Logger::complexToString((**mIntfVoltage)(0, 0)), mVirtualNodes[0]->matrixNodeIndex()); + Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(), + (**mIntfVoltage)(0, 0), mNumFreqs); + SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}", + Logger::complexToString((**mIntfVoltage)(0, 0)), + mVirtualNodes[0]->matrixNodeIndex()); } -void DP::Ph1::ProfileVoltageSource::mnaCompApplyRightSideVectorStampHarm(Matrix &rightVector) { +void DP::Ph1::ProfileVoltageSource::mnaCompApplyRightSideVectorStampHarm( + Matrix &rightVector) { for (UInt freq = 0; freq < mNumFreqs; freq++) { // TODO: Is this correct with two nodes not gnd? - Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(), (**mIntfVoltage)(0, freq), 1, 0, freq); - SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}", Logger::complexToString((**mIntfVoltage)(0, freq)), mVirtualNodes[0]->matrixNodeIndex()); + Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(), + (**mIntfVoltage)(0, freq), 1, 0, freq); + SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}", + Logger::complexToString((**mIntfVoltage)(0, freq)), + mVirtualNodes[0]->matrixNodeIndex()); } } @@ -197,45 +258,63 @@ void DP::Ph1::ProfileVoltageSource::updateVoltage(Real time) { // std::cout << "Update voltage to " << (**mIntfVoltage)(0, 0) << " at " << time << std::endl; } -void DP::Ph1::ProfileVoltageSource::mnaCompPreStep(Real time, Int timeStepCount) { +void DP::Ph1::ProfileVoltageSource::mnaCompPreStep(Real time, + Int timeStepCount) { updateVoltage(time); mnaCompApplyRightSideVectorStamp(**mRightVector); } -void DP::Ph1::ProfileVoltageSource::MnaPreStepHarm::execute(Real time, Int timeStepCount) { +void DP::Ph1::ProfileVoltageSource::MnaPreStepHarm::execute(Real time, + Int timeStepCount) { mVoltageSource.updateVoltage(time); - mVoltageSource.mnaCompApplyRightSideVectorStampHarm(**mVoltageSource.mRightVector); + mVoltageSource.mnaCompApplyRightSideVectorStampHarm( + **mVoltageSource.mRightVector); } -void DP::Ph1::ProfileVoltageSource::mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) { mnaCompUpdateCurrent(**leftVector); } +void DP::Ph1::ProfileVoltageSource::mnaCompPostStep( + Real time, Int timeStepCount, Attribute::Ptr &leftVector) { + mnaCompUpdateCurrent(**leftVector); +} -void DP::Ph1::ProfileVoltageSource::MnaPostStepHarm::execute(Real time, Int timeStepCount) { mVoltageSource.mnaCompUpdateCurrent(**mLeftVectors[0]); } +void DP::Ph1::ProfileVoltageSource::MnaPostStepHarm::execute( + Real time, Int timeStepCount) { + mVoltageSource.mnaCompUpdateCurrent(**mLeftVectors[0]); +} -void DP::Ph1::ProfileVoltageSource::mnaCompUpdateCurrent(const Matrix &leftVector) { +void DP::Ph1::ProfileVoltageSource::mnaCompUpdateCurrent( + const Matrix &leftVector) { for (UInt freq = 0; freq < mNumFreqs; freq++) { - (**mIntfCurrent)(0, freq) = Math::complexFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(), mNumFreqs, freq); + (**mIntfCurrent)(0, freq) = Math::complexFromVectorElement( + leftVector, mVirtualNodes[0]->matrixNodeIndex(), mNumFreqs, freq); } } -void DP::Ph1::ProfileVoltageSource::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ +void DP::Ph1::ProfileVoltageSource::daeResidual(double ttime, + const double state[], + const double dstate_dt[], + double resid[], + std::vector &off) { + /* New state vector definintion: + * state[0]=node0_voltage + * state[1]=node1_voltage + * .... + * state[n]=noden_voltage + * state[n+1]=component0_voltage + * state[n+2]=component0_inductance (not yet implemented) + * ... + * state[m-1]=componentm_voltage + * state[m]=componentm_inductance + */ int Pos1 = matrixNodeIndex(0); int Pos2 = matrixNodeIndex(1); - int c_offset = off[0] + off[1]; // current offset for component - int n_offset_1 = c_offset + Pos1 + 1; // current offset for first nodal equation - int n_offset_2 = c_offset + Pos2 + 1; // current offset for second nodal equation - resid[c_offset] = (state[Pos2] - state[Pos1]) - state[c_offset]; // Voltage equation for Resistor + int c_offset = off[0] + off[1]; // current offset for component + int n_offset_1 = + c_offset + Pos1 + 1; // current offset for first nodal equation + int n_offset_2 = + c_offset + Pos2 + 1; // current offset for second nodal equation + resid[c_offset] = (state[Pos2] - state[Pos1]) - + state[c_offset]; // Voltage equation for Resistor // resid[++c_offset] = ; //TODO : add inductance equation resid[n_offset_1] += (**mIntfCurrent)(0, 0).real(); resid[n_offset_2] += (**mIntfCurrent)(0, 0).real(); diff --git a/dpsim-models/src/DP/DP_Ph1_RXLoadSwitch.cpp b/dpsim-models/src/DP/DP_Ph1_RXLoadSwitch.cpp index 79d50e3a62..e1b3d48c1e 100644 --- a/dpsim-models/src/DP/DP_Ph1_RXLoadSwitch.cpp +++ b/dpsim-models/src/DP/DP_Ph1_RXLoadSwitch.cpp @@ -132,3 +132,7 @@ void DP::Ph1::RXLoadSwitch::updateSwitchState(Real time) { } } } + +Bool DP::Ph1::RXLoadSwitch::hasParameterChanged() { + return mSubSwitch->hasParameterChanged(); +}; diff --git a/dpsim-models/src/DP/DP_Ph1_Resistor.cpp b/dpsim-models/src/DP/DP_Ph1_Resistor.cpp index 3ef1f4fb28..c68a59fd02 100644 --- a/dpsim-models/src/DP/DP_Ph1_Resistor.cpp +++ b/dpsim-models/src/DP/DP_Ph1_Resistor.cpp @@ -164,6 +164,7 @@ void DP::Ph1::Resistor::mnaCompUpdateCurrentHarm() { } } +// #### Tear Methods #### void DP::Ph1::Resistor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { Math::addToMatrixElement(tearMatrix, mTearIdx, mTearIdx, Complex(**mResistance, 0)); @@ -174,31 +175,15 @@ void DP::Ph1::Resistor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { void DP::Ph1::Resistor::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector &off) { - // new state vector definintion: - // state[0]=node0_voltage - // state[1]=node1_voltage - // .... - // state[n]=noden_voltage - // state[n+1]=component0_voltage - // state[n+2]=component0_inductance (not yet implemented) - // ... - // state[m-1]=componentm_voltage - // state[m]=componentm_inductance - // ... - // state[x] = nodal_equation_1 - // state[x+1] = nodal_equation_2 - // ... - int Pos1 = matrixNodeIndex(0); int Pos2 = matrixNodeIndex(1); - int c_offset = off[0] + off[1]; //current offset for component + int c_offset = off[0] + off[1]; // Current offset for component int n_offset_1 = - c_offset + Pos1 + 1; // current offset for first nodal equation + c_offset + Pos1 + 1; // Current offset for first nodal equation int n_offset_2 = - c_offset + Pos2 + 1; // current offset for second nodal equation + c_offset + Pos2 + 1; // Current offset for second nodal equation resid[c_offset] = (state[Pos2] - state[Pos1]) - state[c_offset]; // Voltage equation for Resistor - //resid[c_offset+1] = ; //TODO : add inductance equation resid[n_offset_1] += 1.0 / **mResistance * state[c_offset]; resid[n_offset_2] += 1.0 / **mResistance * state[c_offset]; off[1] += 1; diff --git a/dpsim-models/src/DP/DP_Ph1_Switch.cpp b/dpsim-models/src/DP/DP_Ph1_Switch.cpp index 6f7f24d35d..2f159398ed 100644 --- a/dpsim-models/src/DP/DP_Ph1_Switch.cpp +++ b/dpsim-models/src/DP/DP_Ph1_Switch.cpp @@ -107,3 +107,13 @@ void DP::Ph1::Switch::mnaCompPostStep(Real time, Int timeStepCount, mnaCompUpdateVoltage(**leftVector); mnaCompUpdateCurrent(**leftVector); } + +Bool DP::Ph1::Switch::hasParameterChanged() { + // Check if state of switch changed + if (!(mIsClosedPrev == this->mnaIsClosed())) { + mIsClosedPrev = this->mnaIsClosed(); + return 1; //recompute system matrix + } else { + return 0; // do not recompute system matrix + } +}; diff --git a/dpsim-models/src/DP/DP_Ph1_Transformer.cpp b/dpsim-models/src/DP/DP_Ph1_Transformer.cpp index b8b1084731..60f4d9003d 100644 --- a/dpsim-models/src/DP/DP_Ph1_Transformer.cpp +++ b/dpsim-models/src/DP/DP_Ph1_Transformer.cpp @@ -30,7 +30,7 @@ DP::Ph1::Transformer::Transformer(String uid, String name, /// DEPRECATED: Delete method SimPowerComp::Ptr DP::Ph1::Transformer::clone(String name) { auto copy = Transformer::make(name, mLogLevel); - copy->setParameters(**mNominalVoltageEnd1, **mNominalVoltageEnd2, + copy->setParameters(mNominalVoltageEnd1, mNominalVoltageEnd2, std::abs(**mRatio), std::arg(**mRatio), **mResistance, **mInductance); return copy; @@ -47,7 +47,7 @@ void DP::Ph1::Transformer::setParameters(Real nomVoltageEnd1, SPDLOG_LOGGER_INFO( mSLog, "Nominal Voltage End 1={} [V] Nominal Voltage End 2={} [V]", - **mNominalVoltageEnd1, **mNominalVoltageEnd2); + mNominalVoltageEnd1, mNominalVoltageEnd2); SPDLOG_LOGGER_INFO( mSLog, "Resistance={} [Ohm] Inductance={} [Ohm] (referred to primary side)", @@ -81,14 +81,14 @@ void DP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { std::shared_ptr> tmp = mTerminals[0]; mTerminals[0] = mTerminals[1]; mTerminals[1] = tmp; - Real tmpVolt = **mNominalVoltageEnd1; - **mNominalVoltageEnd1 = **mNominalVoltageEnd2; - **mNominalVoltageEnd2 = tmpVolt; + Real tmpVolt = mNominalVoltageEnd1; + mNominalVoltageEnd1 = mNominalVoltageEnd2; + mNominalVoltageEnd2 = tmpVolt; SPDLOG_LOGGER_INFO(mSLog, "Switching terminals to have first terminal at " "higher voltage side. Updated parameters: "); SPDLOG_LOGGER_INFO( mSLog, "Nominal Voltage End 1 = {} [V] Nominal Voltage End 2 = {} [V]", - **mNominalVoltageEnd1, **mNominalVoltageEnd2); + mNominalVoltageEnd1, mNominalVoltageEnd2); SPDLOG_LOGGER_INFO(mSLog, "Tap Ratio = {} [ ] Phase Shift = {} [deg]", std::abs(**mRatio), std::arg(**mRatio)); } @@ -130,7 +130,7 @@ void DP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { Real qSnub = Q_SNUB_TRANSFORMER * **mRatedPower; // A snubber conductance is added on the higher voltage side - mSnubberResistance1 = std::pow(std::abs(**mNominalVoltageEnd1), 2) / pSnub; + mSnubberResistance1 = std::pow(std::abs(mNominalVoltageEnd1), 2) / pSnub; mSubSnubResistor1 = std::make_shared(**mName + "_snub_res1", mLogLevel); mSubSnubResistor1->setParameters(mSnubberResistance1); @@ -144,7 +144,7 @@ void DP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); // A snubber conductance is added on the lower voltage side - mSnubberResistance2 = std::pow(std::abs(**mNominalVoltageEnd2), 2) / pSnub; + mSnubberResistance2 = std::pow(std::abs(mNominalVoltageEnd2), 2) / pSnub; mSubSnubResistor2 = std::make_shared(**mName + "_snub_res2", mLogLevel); mSubSnubResistor2->setParameters(mSnubberResistance2); @@ -167,7 +167,7 @@ void DP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { // A snubber capacitance is added to lower voltage side mSnubberCapacitance2 = - qSnub / std::pow(std::abs(**mNominalVoltageEnd2), 2) / omega; + qSnub / std::pow(std::abs(mNominalVoltageEnd2), 2) / omega; mSubSnubCapacitor2 = std::make_shared(**mName + "_snub_cap2", mLogLevel); mSubSnubCapacitor2->setParameters(mSnubberCapacitance2); diff --git a/dpsim-models/src/DP/DP_Ph1_VoltageSource.cpp b/dpsim-models/src/DP/DP_Ph1_VoltageSource.cpp index dc825e2e28..5c79c9fe51 100644 --- a/dpsim-models/src/DP/DP_Ph1_VoltageSource.cpp +++ b/dpsim-models/src/DP/DP_Ph1_VoltageSource.cpp @@ -286,17 +286,17 @@ void DP::Ph1::VoltageSource::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ + /* New state vector definintion: + * state[0]=node0_voltage + * state[1]=node1_voltage + * .... + * state[n]=noden_voltage + * state[n+1]=component0_voltage + * state[n+2]=component0_inductance (not yet implemented) + * ... + * state[m-1]=componentm_voltage + * state[m]=componentm_inductance + */ int Pos1 = matrixNodeIndex(0); int Pos2 = matrixNodeIndex(1); diff --git a/dpsim-models/src/DP/DP_Ph1_varResSwitch.cpp b/dpsim-models/src/DP/DP_Ph1_varResSwitch.cpp index c233ea6d09..8634622c1e 100644 --- a/dpsim-models/src/DP/DP_Ph1_varResSwitch.cpp +++ b/dpsim-models/src/DP/DP_Ph1_varResSwitch.cpp @@ -103,11 +103,8 @@ void DP::Ph1::varResSwitch::mnaCompUpdateCurrent(const Matrix &leftVector) { } Bool DP::Ph1::varResSwitch::hasParameterChanged() { - //Get present state - Bool presentState = this->mnaIsClosed(); - // Check if state of switch changed from open to closed - if (!(mPrevState == presentState)) { + if (!(mIsClosedPrev == this->mnaIsClosed())) { // Switch is closed : change with 1/mDeltaRes if (this->mnaIsClosed() == true) { // mClosedResistance= 1./mDeltaRes*mPrevRes; @@ -117,7 +114,7 @@ Bool DP::Ph1::varResSwitch::hasParameterChanged() { if (**mClosedResistance < mInitClosedRes) { **mClosedResistance = mInitClosedRes; mPrevRes = **mClosedResistance; - mPrevState = this->mnaIsClosed(); + mIsClosedPrev = this->mnaIsClosed(); } } // Switch is opened : change with mDeltaRes @@ -128,7 +125,7 @@ Bool DP::Ph1::varResSwitch::hasParameterChanged() { if (**mOpenResistance > mInitOpenRes) { **mOpenResistance = mInitOpenRes; mPrevRes = **mOpenResistance; - mPrevState = this->mnaIsClosed(); + mIsClosedPrev = this->mnaIsClosed(); } } return 1; //recompute system matrix @@ -142,7 +139,7 @@ void DP::Ph1::varResSwitch::setInitParameters(Real timestep) { mDeltaResClosed = 0; // mDeltaResOpen = 1.5; // assumption for 1ms step size mDeltaResOpen = 0.5 * timestep / 0.001 + 1; - mPrevState = **mIsClosed; + mIsClosedPrev = **mIsClosed; mPrevRes = (**mIsClosed) ? **mClosedResistance : **mOpenResistance; mInitClosedRes = **mClosedResistance; mInitOpenRes = **mOpenResistance; diff --git a/dpsim-models/src/DP/DP_Ph3_Capacitor.cpp b/dpsim-models/src/DP/DP_Ph3_Capacitor.cpp index 5233267620..a857aca65c 100644 --- a/dpsim-models/src/DP/DP_Ph3_Capacitor.cpp +++ b/dpsim-models/src/DP/DP_Ph3_Capacitor.cpp @@ -54,16 +54,6 @@ void DP::Ph3::Capacitor::initializeFromNodesAndTerminals(Real frequency) { **mIntfCurrent = susceptance * **mIntfVoltage; SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialize from power flow ---"); - // << "Impedance: " << impedance << std::endl - // << "Voltage across: " << std::abs((**mIntfVoltage)(0,0)) - // << "<" << Math::phaseDeg((**mIntfVoltage)(0,0)) << std::endl - // << "Current: " << std::abs((**mIntfCurrent)(0,0)) - // << "<" << Math::phaseDeg((**mIntfCurrent)(0,0)) << std::endl - // << "Terminal 0 voltage: " << std::abs(initialSingleVoltage(0)) - // << "<" << Math::phaseDeg(initialSingleVoltage(0)) << std::endl - // << "Terminal 1 voltage: " << std::abs(initialSingleVoltage(1)) - // << "<" << Math::phaseDeg(initialSingleVoltage(1)) << std::endl - // << "--- Power flow initialization finished ---" << std::endl; } void DP::Ph3::Capacitor::initVars(Real omega, Real timeStep) { @@ -83,10 +73,6 @@ void DP::Ph3::Capacitor::initVars(Real omega, Real timeStep) { Complex(equivCondReal(2, 1), equivCondImag(2, 1)), Complex(equivCondReal(2, 2), equivCondImag(2, 2)); - // since equivCondReal == a.inverse() - // and - /*Matrix mPrevVoltCoeffReal = a.inverse(); - Matrix mPrevVoltCoeffImag = -b * a.inverse();*/ Matrix mPrevVoltCoeffReal = equivCondReal; Matrix mPrevVoltCoeffImag = -b * equivCondReal; @@ -108,32 +94,6 @@ void DP::Ph3::Capacitor::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { updateMatrixNodeIndices(); initVars(omega, timeStep); - //Matrix equivCondReal = 2.0 * mCapacitance / timeStep; - //Matrix equivCondImag = omega * mCapacitance; - //mEquivCond << - // Complex(equivCondReal(0, 0), equivCondImag(0, 0)), - // Complex(equivCondReal(1, 0), equivCondImag(1, 0)), - // Complex(equivCondReal(2, 0), equivCondImag(2, 0)); - - // TODO: something is wrong here -- from Ph1_Capacitor - /*Matrix prevVoltCoeffReal = 2.0 * mCapacitance / timeStep; - Matrix prevVoltCoeffImag = - omega * mCapacitance; - mPrevVoltCoeff = Matrix::Zero(3, 1); - mPrevVoltCoeff << - Complex(prevVoltCoeffReal(0, 0), prevVoltCoeffImag(0, 0)), - Complex(prevVoltCoeffReal(1, 0), prevVoltCoeffImag(1, 0)), - Complex(prevVoltCoeffReal(2, 0), prevVoltCoeffImag(2, 0)); - - mEquivCurrent = -**mIntfCurrent + -mPrevVoltCoeff.cwiseProduct( **mIntfVoltage);*/ - // no need to update current now - //**mIntfCurrent = mEquivCond.cwiseProduct(**mIntfVoltage) + mEquivCurrent; - - // mLog.info() << "\n--- MNA Initialization ---" << std::endl - // << "Initial voltage " << Math::abs((**mIntfVoltage)(0,0)) - // << "<" << Math::phaseDeg((**mIntfVoltage)(0,0)) << std::endl - // << "Initial current " << Math::abs((**mIntfCurrent)(0,0)) - // << "<" << Math::phaseDeg((**mIntfCurrent)(0,0)) << std::endl - // << "--- MNA initialization finished ---" << std::endl; } void DP::Ph3::Capacitor::mnaCompApplySystemMatrixStamp( @@ -144,9 +104,6 @@ void DP::Ph3::Capacitor::mnaCompApplySystemMatrixStamp( } void DP::Ph3::Capacitor::mnaCompApplyRightSideVectorStamp(Matrix &rightVector) { - //mCureqr = mCurrr + mGcr * mDeltavr + mGci * mDeltavi; - //mCureqi = mCurri + mGcr * mDeltavi - mGci * mDeltavr; - mEquivCurrent = -**mIntfCurrent + -mPrevVoltCoeff * **mIntfVoltage; if (terminalNotGrounded(0)) { diff --git a/dpsim-models/src/DP/DP_Ph3_Inductor.cpp b/dpsim-models/src/DP/DP_Ph3_Inductor.cpp index be0ff3e8dc..d045bd1e49 100644 --- a/dpsim-models/src/DP/DP_Ph3_Inductor.cpp +++ b/dpsim-models/src/DP/DP_Ph3_Inductor.cpp @@ -54,16 +54,6 @@ void DP::Ph3::Inductor::initializeFromNodesAndTerminals(Real frequency) { //TODO SPDLOG_LOGGER_INFO(mSLog, "--- Initialize according to power flow ---"); - // << "in phase A: " << std::endl - // << "Voltage across: " << std::abs((**mIntfVoltage)(0,0)) - // << "<" << Math::phaseDeg((**mIntfVoltage)(0,0)) << std::endl - // << "Current: " << std::abs((**mIntfCurrent)(0,0)) - // << "<" << Math::phaseDeg((**mIntfCurrent)(0,0)) << std::endl - // << "Terminal 0 voltage: " << std::abs(initialSingleVoltage(0)) - // << "<" << Math::phaseDeg(initialSingleVoltage(0)) << std::endl - // << "Terminal 1 voltage: " << std::abs(initialSingleVoltage(1)) - // << "<" << Math::phaseDeg(initialSingleVoltage(1)) << std::endl - // << "--- Power flow initialization finished ---" << std::endl; } void DP::Ph3::Inductor::initVars(Real omega, Real timeStep) { @@ -89,8 +79,6 @@ void DP::Ph3::Inductor::initVars(Real omega, Real timeStep) { // TODO: check if this is correct or if it should be only computed before the step mEquivCurrent = mEquivCond * **mIntfVoltage + mPrevCurrFac * **mIntfCurrent; - // no need to update this now - //**mIntfCurrent = mEquivCond.cwiseProduct(**mIntfVoltage) + mEquivCurrent; } void DP::Ph3::Inductor::mnaCompInitialize(Real omega, Real timeStep, @@ -100,9 +88,6 @@ void DP::Ph3::Inductor::mnaCompInitialize(Real omega, Real timeStep, SPDLOG_LOGGER_INFO(mSLog, "Initial voltage {}", Math::abs((**mIntfVoltage)(0, 0))); - // << "<" << Math::phaseDeg((**mIntfVoltage)(0,0)) << std::endl - // << "Initial current " << Math::abs((**mIntfCurrent)(0,0)) - // << "<" << Math::phaseDeg((**mIntfCurrent)(0,0)) << std::endl; } void DP::Ph3::Inductor::mnaCompApplySystemMatrixStamp( @@ -193,26 +178,34 @@ void DP::Ph3::Inductor::mnaCompUpdateCurrent(const Matrix &leftVector) { **mIntfCurrent = mEquivCond * **mIntfVoltage + mEquivCurrent; } +// #### Tear Methods #### void DP::Ph3::Inductor::mnaTearInitialize(Real omega, Real timeStep) { initVars(omega, timeStep); } void DP::Ph3::Inductor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { - /* - Math::addToMatrixElement(tearMatrix, mTearIdx, mTearIdx, mEquivCond.cwiseInverse()(0,0)); - */ + // Set diagonal entries + Math::addToMatrixElement(tearMatrix, mTearIdx * 3, mTearIdx * 3, + 1. / mEquivCond(0, 0)); // 1 / + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 1, mTearIdx * 3 + 1, + 1. / mEquivCond(1, 1)); + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 2, mTearIdx * 3 + 2, + 1. / mEquivCond(2, 2)); } void DP::Ph3::Inductor::mnaTearApplyVoltageStamp(Matrix &voltageVector) { - /* - mEquivCurrent = mEquivCond * (**mIntfVoltage)(0,0) + mPrevCurrFac * (**mIntfCurrent)(0,0); - Math::addToVectorElement(voltageVector, mTearIdx, mEquivCurrent .cwiseProduct( mEquivCond.cwiseInverse())); - */ -} - -void DP::Ph3::Inductor::mnaTearPostStep(Complex voltage, Complex current) { - /* - **mIntfVoltage = voltage; - **mIntfCurrent = mEquivCond * voltage + mEquivCurrent; - */ + mEquivCurrent = + mEquivCond * (**mIntfVoltage) + mPrevCurrFac * (**mIntfCurrent); + Math::addToVectorElement(voltageVector, mTearIdx * 3, + mEquivCurrent(0, 0) / mEquivCond(0, 0)); + Math::addToVectorElement(voltageVector, mTearIdx * 3 + 1, + mEquivCurrent(1, 0) / mEquivCond(1, 1)); + Math::addToVectorElement(voltageVector, mTearIdx * 3 + 2, + mEquivCurrent(2, 0) / mEquivCond(2, 2)); +} + +void DP::Ph3::Inductor::mnaTearPostStep(MatrixComp voltage, + MatrixComp current) { + (**mIntfVoltage) = voltage; + (**mIntfCurrent) = mEquivCond * voltage + mEquivCurrent; } diff --git a/dpsim-models/src/DP/DP_Ph3_PiLine.cpp b/dpsim-models/src/DP/DP_Ph3_PiLine.cpp new file mode 100644 index 0000000000..73a66cdbf8 --- /dev/null +++ b/dpsim-models/src/DP/DP_Ph3_PiLine.cpp @@ -0,0 +1,250 @@ +/* Author: Christoph Wirtz + * SPDX-FileCopyrightText: 2025 FGH e.V. + * SPDX-License-Identifier: MPL-2.0 + */ + +#include + +using namespace CPS; + +DP::Ph3::PiLine::PiLine(String uid, String name, Logger::Level logLevel) + : Base::Ph3::PiLine(mAttributes), + CompositePowerComp(uid, name, true, true, logLevel) { + mPhaseType = PhaseType::ABC; + setVirtualNodeNumber(1); + setTerminalNumber(2); + + SPDLOG_LOGGER_INFO(mSLog, "Create {} {}", this->type(), name); + **mIntfVoltage = MatrixComp::Zero(3, 1); + **mIntfCurrent = MatrixComp::Zero(3, 1); +} + +///DEPRECATED: Remove method +SimPowerComp::Ptr DP::Ph3::PiLine::clone(String name) { + auto copy = PiLine::make(name, mLogLevel); + copy->setParameters(**mSeriesRes, **mSeriesInd, **mParallelCap, + **mParallelCond); + return copy; +} + +void DP::Ph3::PiLine::initializeFromNodesAndTerminals(Real frequency) { + + // Static calculation + Real omega = 2. * PI * frequency; + MatrixComp impedance = MatrixComp::Zero(3, 3); + impedance << Complex((**mSeriesRes)(0, 0), omega * (**mSeriesInd)(0, 0)), + Complex((**mSeriesRes)(0, 1), omega * (**mSeriesInd)(0, 1)), + Complex((**mSeriesRes)(0, 2), omega * (**mSeriesInd)(0, 2)), + Complex((**mSeriesRes)(1, 0), omega * (**mSeriesInd)(1, 0)), + Complex((**mSeriesRes)(1, 1), omega * (**mSeriesInd)(1, 1)), + Complex((**mSeriesRes)(1, 2), omega * (**mSeriesInd)(1, 2)), + Complex((**mSeriesRes)(2, 0), omega * (**mSeriesInd)(2, 0)), + Complex((**mSeriesRes)(2, 1), omega * (**mSeriesInd)(2, 1)), + Complex((**mSeriesRes)(2, 2), omega * (**mSeriesInd)(2, 2)); + MatrixComp vInitABC = MatrixComp::Zero(3, 1); + vInitABC(0, 0) = RMS3PH_TO_PEAK1PH * initialSingleVoltage(1) - + RMS3PH_TO_PEAK1PH * initialSingleVoltage(0); + vInitABC(1, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_B; + vInitABC(2, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_C; + MatrixComp iInit = impedance.inverse() * vInitABC; + **mIntfCurrent = iInit; + **mIntfVoltage = vInitABC; + + // Initialization of virtual node + // Initial voltage of phase B,C is set after A + MatrixComp vInitTerm0 = MatrixComp::Zero(3, 1); + vInitTerm0(0, 0) = RMS3PH_TO_PEAK1PH * initialSingleVoltage(0); + vInitTerm0(1, 0) = vInitTerm0(0, 0) * SHIFT_TO_PHASE_B; + vInitTerm0(2, 0) = vInitTerm0(0, 0) * SHIFT_TO_PHASE_C; + + mVirtualNodes[0]->setInitialVoltage(PEAK1PH_TO_RMS3PH * + (vInitTerm0 + **mSeriesRes * iInit)); + + // Create series sub components + mSubSeriesResistor = + std::make_shared(**mName + "_res", mLogLevel); + mSubSeriesResistor->setParameters(**mSeriesRes); + mSubSeriesResistor->connect({mTerminals[0]->node(), mVirtualNodes[0]}); + mSubSeriesResistor->initialize(mFrequencies); + mSubSeriesResistor->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubSeriesResistor, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + mSubSeriesInductor = + std::make_shared(**mName + "_ind", mLogLevel); + mSubSeriesInductor->setParameters(**mSeriesInd); + mSubSeriesInductor->connect({mVirtualNodes[0], mTerminals[1]->node()}); + mSubSeriesInductor->initialize(mFrequencies); + mSubSeriesInductor->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubSeriesInductor, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + + // By default there is always a small conductance to ground to + // avoid problems with floating nodes. + Matrix defaultParallelCond = Matrix::Zero(3, 3); + defaultParallelCond << 1e-6, 0, 0, 0, 1e-6, 0, 0, 0, 1e-6; + **mParallelCond = + ((**mParallelCond)(0, 0) > 0) ? **mParallelCond : defaultParallelCond; + + // Create parallel sub components + mSubParallelResistor0 = + std::make_shared(**mName + "_con0", mLogLevel); + mSubParallelResistor0->setParameters(2. * (**mParallelCond).inverse()); + mSubParallelResistor0->connect( + SimNode::List{SimNode::GND, mTerminals[0]->node()}); + mSubParallelResistor0->initialize(mFrequencies); + mSubParallelResistor0->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelResistor0, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + mSubParallelResistor1 = + std::make_shared(**mName + "_con1", mLogLevel); + mSubParallelResistor1->setParameters(2. * (**mParallelCond).inverse()); + mSubParallelResistor1->connect( + SimNode::List{SimNode::GND, mTerminals[1]->node()}); + mSubParallelResistor1->initialize(mFrequencies); + mSubParallelResistor1->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelResistor1, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + if ((**mParallelCap)(0, 0) > 0) { + mSubParallelCapacitor0 = + std::make_shared(**mName + "_cap0", mLogLevel); + mSubParallelCapacitor0->setParameters(**mParallelCap / 2.); + mSubParallelCapacitor0->connect( + SimNode::List{SimNode::GND, mTerminals[0]->node()}); + mSubParallelCapacitor0->initialize(mFrequencies); + mSubParallelCapacitor0->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelCapacitor0, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + + mSubParallelCapacitor1 = + std::make_shared(**mName + "_cap1", mLogLevel); + mSubParallelCapacitor1->setParameters(**mParallelCap / 2.); + mSubParallelCapacitor1->connect( + SimNode::List{SimNode::GND, mTerminals[1]->node()}); + mSubParallelCapacitor1->initialize(mFrequencies); + mSubParallelCapacitor1->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelCapacitor1, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + } + + SPDLOG_LOGGER_INFO( + mSLog, + "\n--- Initialization from powerflow ---" + "\nVoltage across: {:s}" + "\nCurrent: {:s}" + "\nTerminal 0 voltage: {:s}" + "\nTerminal 1 voltage: {:s}" + "\nVirtual Node 1 voltage: {:s}" + "\n--- Initialization from powerflow finished ---", + Logger::matrixCompToString(**mIntfVoltage), + Logger::matrixCompToString(**mIntfCurrent), + Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)), + Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)), + Logger::phasorToString(mVirtualNodes[0]->initialSingleVoltage())); +} + +void DP::Ph3::PiLine::mnaParentAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { + // add pre-step dependencies of component itself + prevStepDependencies.push_back(mIntfCurrent); + prevStepDependencies.push_back(mIntfVoltage); + modifiedAttributes.push_back(mRightVector); +} + +void DP::Ph3::PiLine::mnaParentPreStep(Real time, Int timeStepCount) { + // pre-step of component itself + this->mnaApplyRightSideVectorStamp(**mRightVector); +} + +void DP::Ph3::PiLine::mnaParentAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { + // add post-step dependencies of component itself + attributeDependencies.push_back(leftVector); + modifiedAttributes.push_back(mIntfVoltage); + modifiedAttributes.push_back(mIntfCurrent); +} + +void DP::Ph3::PiLine::mnaParentPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) { + // post-step of component itself + this->mnaUpdateVoltage(**leftVector); + this->mnaUpdateCurrent(**leftVector); +} + +void DP::Ph3::PiLine::mnaCompUpdateVoltage(const Matrix &leftVector) { + // v1 - v0 + **mIntfVoltage = MatrixComp::Zero(3, 1); + if (terminalNotGrounded(1)) { + (**mIntfVoltage)(0, 0) = + Math::complexFromVectorElement(leftVector, matrixNodeIndex(1, 0)); + (**mIntfVoltage)(1, 0) = + Math::complexFromVectorElement(leftVector, matrixNodeIndex(1, 1)); + (**mIntfVoltage)(2, 0) = + Math::complexFromVectorElement(leftVector, matrixNodeIndex(1, 2)); + } + if (terminalNotGrounded(0)) { + (**mIntfVoltage)(0, 0) = + (**mIntfVoltage)(0, 0) - + Math::complexFromVectorElement(leftVector, matrixNodeIndex(0, 0)); + (**mIntfVoltage)(1, 0) = + (**mIntfVoltage)(1, 0) - + Math::complexFromVectorElement(leftVector, matrixNodeIndex(0, 1)); + (**mIntfVoltage)(2, 0) = + (**mIntfVoltage)(2, 0) - + Math::complexFromVectorElement(leftVector, matrixNodeIndex(0, 2)); + } +} + +void DP::Ph3::PiLine::mnaCompUpdateCurrent(const Matrix &leftVector) { + **mIntfCurrent = mSubSeriesInductor->intfCurrent(); +} + +// #### Tear Methods #### +MNAInterface::List DP::Ph3::PiLine::mnaTearGroundComponents() { + MNAInterface::List gndComponents; + + gndComponents.push_back(mSubParallelResistor0); + gndComponents.push_back(mSubParallelResistor1); + + if ((**mParallelCap)(0, 0) > 0) { + gndComponents.push_back(mSubParallelCapacitor0); + gndComponents.push_back(mSubParallelCapacitor1); + } + + return gndComponents; +} + +void DP::Ph3::PiLine::mnaTearInitialize(Real omega, Real timeStep) { + mSubSeriesResistor->mnaTearSetIdx(mTearIdx); + mSubSeriesResistor->mnaTearInitialize(omega, timeStep); + mSubSeriesInductor->mnaTearSetIdx(mTearIdx); + mSubSeriesInductor->mnaTearInitialize(omega, timeStep); +} + +void DP::Ph3::PiLine::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + mSubSeriesResistor->mnaTearApplyMatrixStamp(tearMatrix); + mSubSeriesInductor->mnaTearApplyMatrixStamp(tearMatrix); +} + +void DP::Ph3::PiLine::mnaTearApplyVoltageStamp(Matrix &voltageVector) { + mSubSeriesInductor->mnaTearApplyVoltageStamp(voltageVector); +} + +void DP::Ph3::PiLine::mnaTearPostStep(MatrixComp voltage, MatrixComp current) { + mSubSeriesInductor->mnaTearPostStep(voltage - (**mSeriesRes * current), + current); + (**mIntfCurrent) = mSubSeriesInductor->intfCurrent(); +} diff --git a/dpsim-models/src/DP/DP_Ph3_Resistor.cpp b/dpsim-models/src/DP/DP_Ph3_Resistor.cpp index 7ca6a3a828..bdfb4dba6a 100644 --- a/dpsim-models/src/DP/DP_Ph3_Resistor.cpp +++ b/dpsim-models/src/DP/DP_Ph3_Resistor.cpp @@ -110,8 +110,21 @@ void DP::Ph3::Resistor::mnaCompUpdateVoltage(const Matrix &leftVector) { void DP::Ph3::Resistor::mnaCompUpdateCurrent(const Matrix &leftVector) { **mIntfCurrent = (**mResistance).inverse() * **mIntfVoltage; - SPDLOG_LOGGER_DEBUG(mSLog, "Current A: {} < {}", + std::abs((**mIntfCurrent)(0, 0)), std::arg((**mIntfCurrent)(0, 0))); } + +// #### Tear Methods #### +void DP::Ph3::Resistor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + MatrixFixedSizeComp<3, 3> conductance = Matrix::Zero(3, 3); + conductance.real() = (**mResistance).inverse(); + // Set diagonal entries + Math::addToMatrixElement(tearMatrix, mTearIdx * 3, mTearIdx * 3, + 1. / conductance(0, 0).real()); // 1 / + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 1, mTearIdx * 3 + 1, + 1. / conductance(1, 1).real()); + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 2, mTearIdx * 3 + 2, + 1. / conductance(2, 2).real()); +} diff --git a/dpsim-models/src/DP/DP_Ph3_SeriesSwitch.cpp b/dpsim-models/src/DP/DP_Ph3_SeriesSwitch.cpp index 2f2e36ecdf..15563759dc 100644 --- a/dpsim-models/src/DP/DP_Ph3_SeriesSwitch.cpp +++ b/dpsim-models/src/DP/DP_Ph3_SeriesSwitch.cpp @@ -21,6 +21,9 @@ DP::Ph3::SeriesSwitch::SeriesSwitch(String uid, String name, void DP::Ph3::SeriesSwitch::initializeFromNodesAndTerminals(Real frequency) { + mTerminals[0]->setPhaseType(PhaseType::ABC); + mTerminals[1]->setPhaseType(PhaseType::ABC); + Real impedance = (**mIsClosed) ? **mClosedResistance : **mOpenResistance; **mIntfVoltage = initialVoltage(1) - initialVoltage(0); **mIntfCurrent = **mIntfVoltage / impedance; @@ -117,3 +120,13 @@ void DP::Ph3::SeriesSwitch::mnaCompUpdateCurrent(const Matrix &leftVector) { std::abs((**mIntfCurrent)(0, 0)), std::arg((**mIntfCurrent)(0, 0))); } + +Bool DP::Ph3::SeriesSwitch::hasParameterChanged() { + // Check if state of switch changed + if (!(mIsClosedPrev == this->mnaIsClosed())) { + mIsClosedPrev = this->mnaIsClosed(); + return 1; //recompute system matrix + } else { + return 0; // do not recompute system matrix + } +}; diff --git a/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQ.cpp b/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQ.cpp index f3ff484338..b2e8f547ca 100644 --- a/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQ.cpp +++ b/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQ.cpp @@ -193,53 +193,6 @@ MatrixComp DP::Ph3::SynchronGeneratorDQ::dq0ToAbcTransform(Real theta, return abcCompVector; } -void DP::Ph3::SynchronGeneratorDQ::trapezoidalFluxStates() { - /* - // Calculation of rotational speed with euler - if (mHasTurbineGovernor == true) - mMechTorque = mTurbineGovernor.step(mOmMech, 1, 300e6 / 555e6, mTimeStep); - - mElecTorque = (mPsid*mIq - mPsiq*mId); - mOmMech = mOmMech + mTimeStep * (1 / (2 * mH) * (mMechTorque - mElecTorque)); - - //Calculation of flux - Matrix A = (mResistanceMat*mReactanceMat - mOmMech*mOmegaFluxMat); - Matrix B = Matrix::Identity(7, 7); - - if (numMethod == NumericalMethod::Trapezoidal_flux) - Fluxes = Math::StateSpaceTrapezoidal(Fluxes, A, B, mTimeStep*mBase_OmElec, dqVoltages); - else - Fluxes = Math::StateSpaceEuler(Fluxes, A, B, mTimeStep*mBase_OmElec, dqVoltages); - - // Calculation of currents based on inverse of inductance matrix - mId = ((mLlfd*mLlkd + mLmd*(mLlfd + mLlkd))*mPsid - mLmd*mLlkd*mPsifd - mLlfd*mLmd*mPsikd) / detLd; - mIfd = (mLlkd*mLmd*mPsid - (mLl*mLlkd + mLmd*(mLl + mLlkd))*mPsifd + mLmd*mLl*mPsikd) / detLd; - mIkd = (mLmd*mLlfd*mPsid + mLmd*mLl*mPsifd - (mLmd*(mLlfd + mLl) + mLl*mLlfd)*mPsikd) / detLd; - mIq = ((mLlkq1*mLlkq2 + mLmq*(mLlkq1 + mLlkq2))*mPsiq - mLmq*mLlkq2*mPsikq1 - mLmq*mLlkq1*mPsikq2) / detLq; - mIkq1 = (mLmq*mLlkq2*mPsiq - (mLmq*(mLlkq2 + mLl) + mLl*mLlkq2)*mPsikq1 + mLmq*mLl*mPsikq2) / detLq; - mIkq2 = (mLmq*mLlkq1*mPsiq + mLmq*mLl*mPsikq1 - (mLmq*(mLlkq1 + mLl) + mLl*mLlkq1)*mPsikq2) / detLq; - mI0 = -mPsi0 / mLl; - */ -} +void DP::Ph3::SynchronGeneratorDQ::trapezoidalFluxStates() {} -void DP::Ph3::SynchronGeneratorDQ::trapezoidalCurrentStates() { - /* - Matrix A = (mReactanceMat*mResistanceMat); - Matrix B = mReactanceMat; - Matrix C = Matrix::Zero(7, 1); - C(0, 0) = -mOmMech*mPsid; - C(1, 0) = mOmMech*mPsiq; - C = mReactanceMat*C; - - dqCurrents = Math::StateSpaceTrapezoidal(dqCurrents, A, B, C, mTimeStep*mOmMech, dqVoltages); - - //Calculation of currents based on inverse of inductance matrix - mPsiq = -(mLl + mLmq)*mIq + mLmq*mIkq1 + mLmq*mIkq2; - mPsid = -(mLl + mLmd)*mId + mLmd*mIfd + mLmd*mIkd; - mPsi0 = -mLl*mI0; - mPsikq1 = -mLmq*mIq + (mLlkq1 + mLmq)*mIkq1 + mLmq*mIkq2; - mPsikq2 = -mLmq*mIq + mLmq*mIkq1 + (mLlkq2 + mLmq)*mIkq2; - mPsifd = -mLmd*mId + (mLlfd + mLmd)*mIfd + mLmd*mIkd; - mPsikd = -mLmd*mId + mLmd*mIfd + (mLlkd + mLmd)*mIkd; - */ -} +void DP::Ph3::SynchronGeneratorDQ::trapezoidalCurrentStates() {} diff --git a/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQODE.cpp b/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQODE.cpp index c755d29647..b3fb4212d4 100644 --- a/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQODE.cpp +++ b/dpsim-models/src/DP/DP_Ph3_SynchronGeneratorDQODE.cpp @@ -113,8 +113,8 @@ void DP::Ph3::SynchronGeneratorDQODE::odeStateSpace(double t, const double y[], ydot[mDim - 2] = (y[mDim - 1] - 1) * mBase_OmMech; /* Auxiliary variables to compute - * T_e= lambda_d * i_q - lambda_q * i_d - * needed for omega: */ + * T_e= lambda_d * i_q - lambda_q * i_d + * needed for omega: */ realtype i_d = 0, i_q = 0; // Compute new currents (depending on updated fluxes) for (int i = 0; i < mDim - 2; i++) { diff --git a/dpsim-models/src/DP/DP_Ph3_VoltageSource.cpp b/dpsim-models/src/DP/DP_Ph3_VoltageSource.cpp index 649431da27..b69897154e 100644 --- a/dpsim-models/src/DP/DP_Ph3_VoltageSource.cpp +++ b/dpsim-models/src/DP/DP_Ph3_VoltageSource.cpp @@ -35,13 +35,6 @@ void DP::Ph3::VoltageSource::setParameters(Complex voltageRef) { void DP::Ph3::VoltageSource::initializeFromNodesAndTerminals(Real frequency) { if (**mVoltageRef == Complex(0, 0)) **mVoltageRef = initialSingleVoltage(1) - initialSingleVoltage(0); - - // mLog.info() << "--- Initialize according to power flow ---" << std::endl; - // mLog.info() << "Terminal 0 voltage: " << std::abs(initialSingleVoltage(0)) - // << "<" << std::arg(initialSingleVoltage(0)) << std::endl; - // mLog.info() << "Terminal 1 voltage: " << std::abs(initialSingleVoltage(1)) - // << "<" << std::arg(initialSingleVoltage(1)) << std::endl; - // mLog.info() << "Voltage across: " << std::abs(mVoltageRef->get()) << "<" << std::arg(mVoltageRef->get()) << std::endl; } void DP::Ph3::VoltageSource::mnaCompInitialize( @@ -106,16 +99,6 @@ void DP::Ph3::VoltageSource::mnaCompApplySystemMatrixStamp( mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(1, 2), Complex(1, 0)); } - - // mLog.info() << "--- System matrix stamp ---" << std::endl; - // if (terminalNotGrounded(0)) { - // mLog.info() << "Add " << Complex(-1, 0) << " to " << matrixNodeIndex(0) << "," << mVirtualNodes[0]->matrixNodeIndex(PhaseType::A) << std::endl; - // mLog.info() << "Add " << Complex(-1, 0) << " to " << mVirtualNodes[0]->matrixNodeIndex(PhaseType::A) << "," << matrixNodeIndex(0) << std::endl; - // } - // if (terminalNotGrounded(1)) { - // mLog.info() << "Add " << Complex(1, 0) << " to " << mVirtualNodes[0]->matrixNodeIndex(PhaseType::A) << "," << matrixNodeIndex(1) << std::endl; - // mLog.info() << "Add " << Complex(1, 0) << " to " << matrixNodeIndex(1) << "," << mVirtualNodes[0]->matrixNodeIndex(PhaseType::A) << std::endl; - // } } void DP::Ph3::VoltageSource::mnaCompApplyRightSideVectorStamp( @@ -129,8 +112,6 @@ void DP::Ph3::VoltageSource::mnaCompApplyRightSideVectorStamp( Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), (**mIntfVoltage)(2, 0)); - - //mLog.debug() << "Add " << (**mIntfVoltage)(0,0) << " to source vector " << mVirtualNodes[0]->matrixNodeIndex(PhaseType::A) << std::endl; } void DP::Ph3::VoltageSource::updateVoltage(Real time) { @@ -188,30 +169,7 @@ void DP::Ph3::VoltageSource::mnaCompUpdateCurrent(const Matrix &leftVector) { void DP::Ph3::VoltageSource::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], - std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ - - //int Pos1 = matrixNodeIndex(0); - //int Pos2 = matrixNodeIndex(1); - //int c_offset = off[0] + off[1]; //current offset for component - //int n_offset_1 = c_offset + Pos1 + 1;// current offset for first nodal equation - //int n_offset_2 = c_offset + Pos2 + 1;// current offset for second nodal equation - //resid[c_offset] = (state[Pos2] - state[Pos1]) - state[c_offset]; // Voltage equation for Resistor - ////resid[++c_offset] = ; //TODO : add inductance equation - //resid[n_offset_1] += std::real(current()); - //resid[n_offset_2] += std::real(current()); - //off[1] += 1; -} + std::vector &off) {} Complex DP::Ph3::VoltageSource::daeInitialize() { (**mIntfVoltage)(0, 0) = **mVoltageRef; diff --git a/dpsim-models/src/EMT/EMT_Ph1_Inductor.cpp b/dpsim-models/src/EMT/EMT_Ph1_Inductor.cpp index 63e8a275da..59e2022546 100644 --- a/dpsim-models/src/EMT/EMT_Ph1_Inductor.cpp +++ b/dpsim-models/src/EMT/EMT_Ph1_Inductor.cpp @@ -116,3 +116,25 @@ void EMT::Ph1::Inductor::mnaCompUpdateVoltage(const Matrix &leftVector) { void EMT::Ph1::Inductor::mnaCompUpdateCurrent(const Matrix &leftVector) { (**mIntfCurrent)(0, 0) = mEquivCond * (**mIntfVoltage)(0, 0) + mEquivCurrent; } + +// #### Tear Methods #### +void EMT::Ph1::Inductor::mnaTearInitialize(Real omega, Real timeStep) { + updateMatrixNodeIndices(); + mEquivCond = timeStep / (2.0 * **mInductance); + // Update internal state + mEquivCurrent = mEquivCond * (**mIntfVoltage)(0, 0) + (**mIntfCurrent)(0, 0); +} + +void EMT::Ph1::Inductor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + Math::addToMatrixElement(tearMatrix, mTearIdx, mTearIdx, 1. / mEquivCond); +} + +void EMT::Ph1::Inductor::mnaTearApplyVoltageStamp(Matrix &voltageVector) { + mEquivCurrent = mEquivCond * (**mIntfVoltage)(0, 0) + (**mIntfCurrent)(0, 0); + Math::addToVectorElement(voltageVector, mTearIdx, mEquivCurrent / mEquivCond); +} + +void EMT::Ph1::Inductor::mnaTearPostStep(Complex voltage, Complex current) { + (**mIntfVoltage)(0, 0) = voltage.real(); + (**mIntfCurrent)(0, 0) = mEquivCond * voltage.real() + mEquivCurrent; +} diff --git a/dpsim-models/src/EMT/EMT_Ph1_PiLine.cpp b/dpsim-models/src/EMT/EMT_Ph1_PiLine.cpp new file mode 100644 index 0000000000..b7568fd8c5 --- /dev/null +++ b/dpsim-models/src/EMT/EMT_Ph1_PiLine.cpp @@ -0,0 +1,225 @@ +/* Author: Christoph Wirtz + * SPDX-FileCopyrightText: 2025 FGH e.V. + * SPDX-License-Identifier: MPL-2.0 + */ + +#include + +using namespace CPS; + +EMT::Ph1::PiLine::PiLine(String uid, String name, Logger::Level logLevel) + : Base::Ph1::PiLine(mAttributes), + CompositePowerComp(uid, name, true, true, logLevel) { + setVirtualNodeNumber(1); + setTerminalNumber(2); + + SPDLOG_LOGGER_INFO(mSLog, "Create {} {}", this->type(), name); + **mIntfVoltage = Matrix::Zero(1, 1); + **mIntfCurrent = Matrix::Zero(1, 1); + + mSLog->flush(); +} + +/// DEPRECATED: Delete method +SimPowerComp::Ptr EMT::Ph1::PiLine::clone(String name) { + auto copy = PiLine::make(name, mLogLevel); + copy->setParameters(**mSeriesRes, **mSeriesInd, **mParallelCap, + **mParallelCond); + return copy; +} + +void EMT::Ph1::PiLine::initializeFromNodesAndTerminals(Real frequency) { + + // By default there is always a small conductance to ground to + // avoid problems with floating nodes. + + Real defaultParallelCond = 1e-6; + **mParallelCond = + (**mParallelCond > 0) ? **mParallelCond : defaultParallelCond; + + // Static calculation + Real omega = 2. * PI * frequency; + Complex impedance = {**mSeriesRes, omega * **mSeriesInd}; + Complex voltage = + RMS3PH_TO_PEAK1PH * (initialSingleVoltage(1) - initialSingleVoltage(0)); + (**mIntfVoltage)(0, 0) = voltage.real(); + (**mIntfCurrent)(0, 0) = (voltage / impedance).real(); + + // Initialization of virtual node + mVirtualNodes[0]->setInitialVoltage(initialSingleVoltage(0) + + (**mIntfCurrent)(0, 0) * **mSeriesRes); + + // Create series sub components + mSubSeriesResistor = + std::make_shared(**mName + "_res", mLogLevel); + mSubSeriesResistor->setParameters(**mSeriesRes); + mSubSeriesResistor->connect({mTerminals[0]->node(), mVirtualNodes[0]}); + mSubSeriesResistor->initialize(mFrequencies); + mSubSeriesResistor->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubSeriesResistor, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + mSubSeriesInductor = + std::make_shared(**mName + "_ind", mLogLevel); + mSubSeriesInductor->setParameters(**mSeriesInd); + mSubSeriesInductor->connect({mVirtualNodes[0], mTerminals[1]->node()}); + mSubSeriesInductor->initialize(mFrequencies); + mSubSeriesInductor->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubSeriesInductor, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + + // Create parallel sub components + mSubParallelResistor0 = + std::make_shared(**mName + "_con0", mLogLevel); + mSubParallelResistor0->setParameters(2. / (**mParallelCond)); + mSubParallelResistor0->connect( + SimNode::List{SimNode::GND, mTerminals[0]->node()}); + mSubParallelResistor0->initialize(mFrequencies); + mSubParallelResistor0->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelResistor0, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + mSubParallelResistor1 = + std::make_shared(**mName + "_con1", mLogLevel); + mSubParallelResistor1->setParameters(2. / (**mParallelCond)); + mSubParallelResistor1->connect( + SimNode::List{SimNode::GND, mTerminals[1]->node()}); + mSubParallelResistor1->initialize(mFrequencies); + mSubParallelResistor1->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelResistor1, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, false); + + if ((**mParallelCap) > 0) { + mSubParallelCapacitor0 = + std::make_shared(**mName + "_cap0", mLogLevel); + mSubParallelCapacitor0->setParameters(**mParallelCap / 2.); + mSubParallelCapacitor0->connect( + SimNode::List{SimNode::GND, mTerminals[0]->node()}); + mSubParallelCapacitor0->initialize(mFrequencies); + mSubParallelCapacitor0->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelCapacitor0, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + + mSubParallelCapacitor1 = + std::make_shared(**mName + "_cap1", mLogLevel); + mSubParallelCapacitor1->setParameters(**mParallelCap / 2.); + mSubParallelCapacitor1->connect( + SimNode::List{SimNode::GND, mTerminals[1]->node()}); + mSubParallelCapacitor1->initialize(mFrequencies); + mSubParallelCapacitor1->initializeFromNodesAndTerminals(frequency); + addMNASubComponent(mSubParallelCapacitor1, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + } + + SPDLOG_LOGGER_DEBUG(mSLog, + "\n--debug--" + "\n seriesRes: {:s}" + "\n seriesInd: {:s}" + "\n Impedance: {:s}", + Logger::matrixToString(**mSeriesRes), + Logger::matrixToString(**mSeriesInd), + Logger::complexToString(impedance)); + + SPDLOG_LOGGER_INFO( + mSLog, + "\n--- Initialization from powerflow ---" + "\nVoltage across: {:s}" + "\nCurrent: {:s}" + "\nTerminal 0 voltage: {:s}" + "\nTerminal 1 voltage: {:s}" + "\nVirtual Node 1 voltage: {:s}" + "\n--- Initialization from powerflow finished ---", + Logger::matrixToString(**mIntfVoltage), + Logger::matrixToString(**mIntfCurrent), + Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)), + Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)), + Logger::phasorToString(mVirtualNodes[0]->initialSingleVoltage())); + mSLog->flush(); +} + +void EMT::Ph1::PiLine::mnaParentAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { + prevStepDependencies.push_back(mIntfCurrent); + prevStepDependencies.push_back(mIntfVoltage); + modifiedAttributes.push_back(mRightVector); +} + +void EMT::Ph1::PiLine::mnaParentPreStep(Real time, Int timeStepCount) { + mnaCompApplyRightSideVectorStamp(**mRightVector); +} + +void EMT::Ph1::PiLine::mnaParentAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { + attributeDependencies.push_back(leftVector); + modifiedAttributes.push_back(mIntfVoltage); + modifiedAttributes.push_back(mIntfCurrent); +} + +void EMT::Ph1::PiLine::mnaParentPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) { + mnaCompUpdateVoltage(**leftVector); + mnaCompUpdateCurrent(**leftVector); +} + +void EMT::Ph1::PiLine::mnaCompUpdateVoltage(const Matrix &leftVector) { + (**mIntfVoltage)(0, 0) = 0; + if (terminalNotGrounded(1)) + (**mIntfVoltage)(0, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1)); + if (terminalNotGrounded(0)) + (**mIntfVoltage)(0, 0) = + (**mIntfVoltage)(0, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0)); +} + +void EMT::Ph1::PiLine::mnaCompUpdateCurrent(const Matrix &leftVector) { + **mIntfCurrent = mSubSeriesInductor->intfCurrent(); +} + +// #### Tear Methods #### +MNAInterface::List EMT::Ph1::PiLine::mnaTearGroundComponents() { + MNAInterface::List gndComponents; + + gndComponents.push_back(mSubParallelResistor0); + gndComponents.push_back(mSubParallelResistor1); + + if ((**mParallelCap) > 0) { + gndComponents.push_back(mSubParallelCapacitor0); + gndComponents.push_back(mSubParallelCapacitor1); + } + + return gndComponents; +} + +void EMT::Ph1::PiLine::mnaTearInitialize(Real omega, Real timeStep) { + mSubSeriesResistor->mnaTearSetIdx(mTearIdx); + mSubSeriesResistor->mnaTearInitialize(omega, timeStep); + mSubSeriesInductor->mnaTearSetIdx(mTearIdx); + mSubSeriesInductor->mnaTearInitialize(omega, timeStep); +} + +void EMT::Ph1::PiLine::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + mSubSeriesResistor->mnaTearApplyMatrixStamp(tearMatrix); + mSubSeriesInductor->mnaTearApplyMatrixStamp(tearMatrix); +} + +void EMT::Ph1::PiLine::mnaTearApplyVoltageStamp(Matrix &voltageVector) { + mSubSeriesInductor->mnaTearApplyVoltageStamp(voltageVector); +} + +void EMT::Ph1::PiLine::mnaTearPostStep(Complex voltage, Complex current) { + mSubSeriesInductor->mnaTearPostStep(voltage - current * **mSeriesRes, + current); + (**mIntfCurrent) = mSubSeriesInductor->intfCurrent(); +} diff --git a/dpsim-models/src/EMT/EMT_Ph1_Resistor.cpp b/dpsim-models/src/EMT/EMT_Ph1_Resistor.cpp index a96950151c..210d87b70a 100644 --- a/dpsim-models/src/EMT/EMT_Ph1_Resistor.cpp +++ b/dpsim-models/src/EMT/EMT_Ph1_Resistor.cpp @@ -88,3 +88,8 @@ void EMT::Ph1::Resistor::mnaCompUpdateVoltage(const Matrix &leftVector) { void EMT::Ph1::Resistor::mnaCompUpdateCurrent(const Matrix &leftVector) { (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / **mResistance; } + +// #### Tear Methods #### +void EMT::Ph1::Resistor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + Math::addToMatrixElement(tearMatrix, mTearIdx, mTearIdx, **mResistance); +} diff --git a/dpsim-models/src/EMT/EMT_Ph1_SSNTypeI2T.cpp b/dpsim-models/src/EMT/EMT_Ph1_SSNTypeI2T.cpp new file mode 100644 index 0000000000..ffa8276ed0 --- /dev/null +++ b/dpsim-models/src/EMT/EMT_Ph1_SSNTypeI2T.cpp @@ -0,0 +1,254 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#include + +using namespace CPS; + +EMT::Ph1::SSNTypeI2T::SSNTypeI2T(String uid, String name, + Logger::Level logLevel) + : MNASimPowerComp(uid, name, true, true, logLevel), + mA(mAttributes->create("A")), + mB(mAttributes->create("B")), + mC(mAttributes->create("C")), + mD(mAttributes->create("D")), + mdA(mAttributes->create("dA")), + mdB(mAttributes->create("dB")), + mdC(mAttributes->create("dC")) { + setTerminalNumber(2); + setVirtualNodeNumber(1); + **mIntfVoltage = Matrix::Zero(1, 1); + **mIntfCurrent = Matrix::Zero(1, 1); + mParametersSet = false; +} + +void EMT::Ph1::SSNTypeI2T::setParameters(const Matrix A, const Matrix B, + const Matrix C, const Matrix D) { + try { + if (A.cols() != A.rows()) + throw std::invalid_argument( + "A needs to be quadratic; Set all matrices to scalar zero."); + **mA = A; + mX = Matrix::Zero((**mA).rows(), 1); + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + try { + if (B.rows() != (**mA).cols()) + throw std::invalid_argument( + "Invalid dimensions; rows of B do not match columns and rows of A! " + "Set all matrices to scalar zero."); + if (B.cols() != 1) + throw std::invalid_argument( + "Invalid dimensions; two terminal V-type SSN component only has on " + "external voltage, so column number of B must be one! Set all " + "matrices to scalar zero."); + **mB = B; + mU = Matrix::Zero((**mB).cols(), 1); + mUOld = Matrix::Zero((**mB).cols(), 1); + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + try { + if (C.rows() != 1) + throw std::invalid_argument( + "Invalid dimensions; a two terminal V type SSN component only has " + "one output current! C must have exactly one row! Set all matrices " + "to scalar zero."); + if (C.cols() != (**mA).rows()) + throw std::invalid_argument( + "Invalid dimensions; columns of C do not match rows of A! Set all " + "matrices to scalar zero."); + **mC = C; + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + try { + if (D.rows() != 1) + throw std::invalid_argument( + "Invalid dimensions; a two terminal V type SSN component only has " + "one output current! D must have exactly one row! Set all matrices " + "to scalar zero."); + if (D.cols() != (**mB).cols()) + throw std::invalid_argument( + "Invalid dimensions; columns of D do not match columns of B and rows " + "of input vector u, which need to be one! Set all matrices to scalar " + "zero."); + **mD = D; + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + mParametersSet = true; +} + +SimPowerComp::Ptr EMT::Ph1::SSNTypeI2T::clone(String name) { + auto copy = SSNTypeI2T::make(name, mLogLevel); + copy->setParameters(**mA, **mB, **mC, **mD); + return copy; +} + +void EMT::Ph1::SSNTypeI2T::initializeFromNodesAndTerminals(Real frequency) { + + (**mIntfCurrent)(0, 0) = 0; + (**mIntfVoltage)(0, 0) = 0; + + SPDLOG_LOGGER_INFO(mSLog, + "\n--- Initialization from powerflow ---" + "\nVoltage across: {:f}" + "\nCurrent: {:f}" + "\nTerminal 0 voltage: {:f}" + "\nTerminal 1 voltage: {:f}" + "\n--- Initialization from powerflow finished ---", + (**mIntfVoltage)(0, 0), (**mIntfCurrent)(0, 0), + (RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)).real(), + (RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)).real()); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompInitialize( + Real omega, Real timeStep, Attribute::Ptr leftVector) { + updateMatrixNodeIndices(); + + Math::calculateStateSpaceTrapezoidalMatrices(**mA, **mB, timeStep, **mdA, + **mdB); + mW = Matrix::Zero(1, 1); + mW = (**mC) * (**mdB) + (**mD); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompApplySystemMatrixStamp( + SparseMatrixRow &systemMatrix) { + + //IntfCurrent from terminal 1 (out of node 1, positive) into terminal 2 (negative) + if (terminalNotGrounded(0)) { + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0), + mVirtualNodes[0]->matrixNodeIndex(), -1); + Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(0), -1); + } + if (terminalNotGrounded(1)) { + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1), + mVirtualNodes[0]->matrixNodeIndex(), 1); + Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + matrixNodeIndex(1), 1); + } + //negative entry to close mesh equation (V1-V0) - mW*IntfCurrent = y_hist + Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(), + mVirtualNodes[0]->matrixNodeIndex(), -mW(0, 0)); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompApplyRightSideVectorStamp( + Matrix &rightVector) { + // Update internal state + mYHist = (**mC) * ((**mdA) * mX + (**mdB) * mU); + Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(), + mYHist(0, 0)); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { + + modifiedAttributes.push_back(mRightVector); + prevStepDependencies.push_back(mIntfCurrent); + prevStepDependencies.push_back(mIntfVoltage); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompPreStep(Real time, Int timeStepCount) { + mnaCompApplyRightSideVectorStamp(**mRightVector); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { + attributeDependencies.push_back(leftVector); + modifiedAttributes.push_back(mIntfVoltage); + modifiedAttributes.push_back(mIntfCurrent); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) { + mnaCompUpdateVoltage(**leftVector); + mnaCompUpdateCurrent(**leftVector); + ssnUpdateState(); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompUpdateVoltage(const Matrix &leftVector) { + // v1 - v0 + (**mIntfVoltage)(0, 0) = 0; + if (terminalNotGrounded(1)) + (**mIntfVoltage)(0, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1)); + if (terminalNotGrounded(0)) + (**mIntfVoltage)(0, 0) = + (**mIntfVoltage)(0, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0)); +} + +void EMT::Ph1::SSNTypeI2T::mnaCompUpdateCurrent(const Matrix &leftVector) { + mUOld = mU; + (**mIntfCurrent)(0, 0) = Math::realFromVectorElement( + leftVector, mVirtualNodes[0]->matrixNodeIndex()); + mU = **mIntfCurrent; +} + +void CPS::EMT::Ph1::SSNTypeI2T::setSSNMatricesToZero() { + **mA = Matrix::Zero(1, 1); + **mB = Matrix::Zero(1, 1); + **mC = Matrix::Zero(1, 1); + **mD = Matrix::Zero(1, 1); + + **mdA = Matrix::Zero(1, 1); + **mdB = Matrix::Zero(1, 1); + **mdC = Matrix::Zero(1, 1); + + mX = Matrix::Zero(1, 1); + mU = Matrix::Zero(1, 1); + mUOld = Matrix::Zero(1, 1); +} + +void EMT::Ph1::SSNTypeI2T::ssnUpdateState() { + mX = (**mdA) * mX + (**mdB) * (mU + mUOld); +} + +void EMT::Ph1::SSNTypeI2T::manualInit(Matrix initialState, Matrix initialInput, + Matrix initialOldInput, Real initCurrent, + Real initVoltage) { + try { + if (mParametersSet == false) + throw std::invalid_argument( + "Set parameters first! Setting x, u, u_old to zero."); + if (initialState.cols() != 1) + throw std::invalid_argument("State matrix is a vector; column number " + "must be one. Setting x, u, u_old to zero."); + if (initialState.rows() != (**mA).cols()) + throw std::invalid_argument( + "State row number does not match row and column number of A. Setting " + "x, u, u_old to zero."); + if (initialInput.cols() != 1 || initialOldInput.cols() != 1) + throw std::invalid_argument("Input matrices are vectors; column number " + "must be one. Setting x, u, u_old to zero."); + if (initialInput.rows() != (**mB).cols() || + initialOldInput.rows() != (**mB).cols()) + throw std::invalid_argument("Input vector rows have to match columns of " + "Matrix B; Setting x, u, u_old to zero."); + mX = initialState; + mU = initialInput; + mUOld = initialOldInput; + (**mIntfCurrent)(0, 0) = initCurrent; + (**mIntfVoltage)(0, 0) = initVoltage; + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + (**mIntfCurrent)(0, 0) = 0; + (**mIntfVoltage)(0, 0) = 0; + } +} diff --git a/dpsim-models/src/EMT/EMT_Ph1_SSNTypeV2T.cpp b/dpsim-models/src/EMT/EMT_Ph1_SSNTypeV2T.cpp new file mode 100644 index 0000000000..4b2b50bbed --- /dev/null +++ b/dpsim-models/src/EMT/EMT_Ph1_SSNTypeV2T.cpp @@ -0,0 +1,241 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#include + +using namespace CPS; + +EMT::Ph1::SSNTypeV2T::SSNTypeV2T(String uid, String name, + Logger::Level logLevel) + : MNASimPowerComp(uid, name, true, true, logLevel), + mA(mAttributes->create("A")), + mB(mAttributes->create("B")), + mC(mAttributes->create("C")), + mD(mAttributes->create("D")), + mdA(mAttributes->create("dA")), + mdB(mAttributes->create("dB")), + mdC(mAttributes->create("dC")) { + setTerminalNumber(2); + **mIntfVoltage = Matrix::Zero(1, 1); + **mIntfCurrent = Matrix::Zero(1, 1); + mParametersSet = false; +} + +void EMT::Ph1::SSNTypeV2T::setParameters(const Matrix A, const Matrix B, + const Matrix C, const Matrix D) { + try { + if (A.cols() != A.rows()) + throw std::invalid_argument( + "A needs to be quadratic; Set all matrices to scalar zero."); + **mA = A; + mX = Matrix::Zero((**mA).rows(), 1); + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + try { + if (B.rows() != (**mA).cols()) + throw std::invalid_argument( + "Invalid dimensions; rows of B do not match columns and rows of A! " + "Set all matrices to scalar zero."); + if (B.cols() != 1) + throw std::invalid_argument( + "Invalid dimensions; two terminal V-type SSN component only has on " + "external voltage, so column number of B must be one! Set all " + "matrices to scalar zero."); + **mB = B; + mU = Matrix::Zero((**mB).cols(), 1); + mUOld = Matrix::Zero((**mB).cols(), 1); + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + try { + if (C.rows() != 1) + throw std::invalid_argument( + "Invalid dimensions; a two terminal V type SSN component only has " + "one output current! C must have exactly one row! Set all matrices " + "to scalar zero."); + if (C.cols() != (**mA).rows()) + throw std::invalid_argument( + "Invalid dimensions; columns of C do not match rows of A! Set all " + "matrices to scalar zero."); + **mC = C; + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + try { + if (D.rows() != 1) + throw std::invalid_argument( + "Invalid dimensions; a two terminal V type SSN component only has " + "one output current! D must have exactly one row! Set all matrices " + "to scalar zero."); + if (D.cols() != (**mB).cols()) + throw std::invalid_argument( + "Invalid dimensions; columns of D do not match columns of B and rows " + "of input vector u, which need to be one! Set all matrices to scalar " + "zero."); + **mD = D; + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + setSSNMatricesToZero(); + return; + } + mParametersSet = true; +} + +SimPowerComp::Ptr EMT::Ph1::SSNTypeV2T::clone(String name) { + auto copy = SSNTypeV2T::make(name, mLogLevel); + copy->setParameters(**mA, **mB, **mC, **mD); + return copy; +} + +void EMT::Ph1::SSNTypeV2T::initializeFromNodesAndTerminals(Real frequency) { + + (**mIntfCurrent)(0, 0) = 0; + (**mIntfVoltage)(0, 0) = 0; + + SPDLOG_LOGGER_INFO(mSLog, + "\n--- Initialization from powerflow ---" + "\nVoltage across: {:f}" + "\nCurrent: {:f}" + "\nTerminal 0 voltage: {:f}" + "\nTerminal 1 voltage: {:f}" + "\n--- Initialization from powerflow finished ---", + (**mIntfVoltage)(0, 0), (**mIntfCurrent)(0, 0), + (RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)).real(), + (RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)).real()); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompInitialize( + Real omega, Real timeStep, Attribute::Ptr leftVector) { + updateMatrixNodeIndices(); + + Math::calculateStateSpaceTrapezoidalMatrices(**mA, **mB, timeStep, **mdA, + **mdB); + mW = Matrix::Zero(1, 1); + mW = (**mC) * (**mdB) + (**mD); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompApplySystemMatrixStamp( + SparseMatrixRow &systemMatrix) { + + MNAStampUtils::stampConductance(mW(0, 0), systemMatrix, matrixNodeIndex(0), + matrixNodeIndex(1), terminalNotGrounded(0), + terminalNotGrounded(1), mSLog); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompApplyRightSideVectorStamp( + Matrix &rightVector) { + // Update internal state + mYHist = (**mC) * ((**mdA) * mX + (**mdB) * mU); + if (terminalNotGrounded(0)) + Math::setVectorElement(rightVector, matrixNodeIndex(0), mYHist(0, 0)); + if (terminalNotGrounded(1)) + Math::setVectorElement(rightVector, matrixNodeIndex(1), -mYHist(0, 0)); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { + + modifiedAttributes.push_back(mRightVector); + prevStepDependencies.push_back(mIntfCurrent); + prevStepDependencies.push_back(mIntfVoltage); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompPreStep(Real time, Int timeStepCount) { + mnaCompApplyRightSideVectorStamp(**mRightVector); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { + attributeDependencies.push_back(leftVector); + modifiedAttributes.push_back(mIntfVoltage); + modifiedAttributes.push_back(mIntfCurrent); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompPostStep(Real time, Int timeStepCount, + Attribute::Ptr &leftVector) { + mnaCompUpdateVoltage(**leftVector); + mnaCompUpdateCurrent(**leftVector); + ssnUpdateState(); +} + +void EMT::Ph1::SSNTypeV2T::mnaCompUpdateVoltage(const Matrix &leftVector) { + // v1 - v0 + mUOld = mU; + (**mIntfVoltage)(0, 0) = 0; + if (terminalNotGrounded(1)) + (**mIntfVoltage)(0, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1)); + if (terminalNotGrounded(0)) + (**mIntfVoltage)(0, 0) = + (**mIntfVoltage)(0, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0)); + mU = **mIntfVoltage; +} + +void EMT::Ph1::SSNTypeV2T::mnaCompUpdateCurrent(const Matrix &leftVector) { + **mIntfCurrent = mW * (**mIntfVoltage) + mYHist; +} + +void CPS::EMT::Ph1::SSNTypeV2T::setSSNMatricesToZero() { + **mA = Matrix::Zero(1, 1); + **mB = Matrix::Zero(1, 1); + **mC = Matrix::Zero(1, 1); + **mD = Matrix::Zero(1, 1); + + **mdA = Matrix::Zero(1, 1); + **mdB = Matrix::Zero(1, 1); + **mdC = Matrix::Zero(1, 1); + + mX = Matrix::Zero(1, 1); + mU = Matrix::Zero(1, 1); + mUOld = Matrix::Zero(1, 1); +} + +void EMT::Ph1::SSNTypeV2T::ssnUpdateState() { + mX = (**mdA) * mX + (**mdB) * (mU + mUOld); +} + +void EMT::Ph1::SSNTypeV2T::manualInit(Matrix initialState, Matrix initialInput, + Matrix initialOldInput, Real initCurrent, + Real initVoltage) { + try { + if (mParametersSet == false) + throw std::invalid_argument( + "Set parameters first! Setting x, u, u_old to zero."); + if (initialState.cols() != 1) + throw std::invalid_argument("State matrix is a vector; column number " + "must be one. Setting x, u, u_old to zero."); + if (initialState.rows() != (**mA).cols()) + throw std::invalid_argument( + "State row number does not match row and column number of A. Setting " + "x, u, u_old to zero."); + if (initialInput.cols() != 1 || initialOldInput.cols() != 1) + throw std::invalid_argument("Input matrices are vectors; column number " + "must be one. Setting x, u, u_old to zero."); + if (initialInput.rows() != (**mB).cols() || + initialOldInput.rows() != (**mB).cols()) + throw std::invalid_argument("Input vector rows have to match columns of " + "Matrix B; Setting x, u, u_old to zero."); + mX = initialState; + mU = initialInput; + mUOld = initialOldInput; + (**mIntfCurrent)(0, 0) = initCurrent; + (**mIntfVoltage)(0, 0) = initVoltage; + } catch (std::exception &e) { + SPDLOG_LOGGER_ERROR(mSLog, "Component {} : {}\n", **mName, e.what()); + (**mIntfCurrent)(0, 0) = 0; + (**mIntfVoltage)(0, 0) = 0; + } +} diff --git a/dpsim-models/src/EMT/EMT_Ph1_SSN_Full_Serial_RLC.cpp b/dpsim-models/src/EMT/EMT_Ph1_SSN_Full_Serial_RLC.cpp new file mode 100644 index 0000000000..f46a9ad267 --- /dev/null +++ b/dpsim-models/src/EMT/EMT_Ph1_SSN_Full_Serial_RLC.cpp @@ -0,0 +1,219 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#include + +using namespace CPS; + +EMT::Ph1::SSN::Full_Serial_RLC::Full_Serial_RLC(String uid, String name, + Logger::Level logLevel) + : MNASimPowerComp(uid, name, true, true, logLevel), + Base::Ph1::Resistor(mAttributes), Base::Ph1::Inductor(mAttributes), + Base::Ph1::Capacitor(mAttributes) { + + mPhaseType = PhaseType::Single; + + **mIntfVoltage = Matrix::Zero(1, 1); + **mIntfCurrent = Matrix::Zero(1, 1); + setTerminalNumber(2); +} + +SimPowerComp::Ptr EMT::Ph1::SSN::Full_Serial_RLC::clone(String name) { + auto copy = Full_Serial_RLC::make(name, mLogLevel); + copy->setParameters(**mResistance, **mInductance, **mCapacitance); + return copy; +} + +void EMT::Ph1::SSN::Full_Serial_RLC::initializeFromNodesAndTerminals( + Real frequency) { + + Real omega = 2 * PI * frequency; + + Complex impedance = + Complex((**mResistance), + omega * (**mInductance) - 1. / (omega * (**mCapacitance))); + + Complex vInit = RMS3PH_TO_PEAK1PH * initialSingleVoltage(1) - + RMS3PH_TO_PEAK1PH * initialSingleVoltage(0); + (**mIntfVoltage)(0, 0) = vInit.real(); + (**mIntfCurrent)(0, 0) = (vInit / impedance).real(); + + SPDLOG_LOGGER_INFO(mSLog, + "\n--- Initialization from powerflow ---" + "\nVoltage across: {:f}" + "\nCurrent: {:f}" + "\nTerminal 0 voltage: {:f}" + "\nTerminal 1 voltage: {:f}" + "\n--- Initialization from powerflow finished ---", + (**mIntfVoltage)(0, 0), (**mIntfCurrent)(0, 0), + (RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)).real(), + (RMS3PH_TO_PEAK1PH * initialSingleVoltage(1)).real()); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompInitialize( + Real omega, Real timeStep, Attribute::Ptr leftVector) { + + updateMatrixNodeIndices(); + + mState = Matrix::Zero(2, 1); + mYHistory = 0; + + //Fill mDufourAKHat + //State Equation one: top left entry + mDufourAKHat(0, 0) = + 1. - ((2. * (timeStep * timeStep)) / + (4. * (**mInductance) * (**mCapacitance) + + 2. * timeStep * (**mCapacitance) * (**mResistance) + + timeStep * timeStep)); + //State Equation one: top right entry + mDufourAKHat(0, 1) = + (timeStep / (2. * (**mCapacitance))) * + (1. + ((4. * (**mInductance) * (**mCapacitance) - + 2. * timeStep * (**mResistance) * (**mCapacitance) - + (timeStep * timeStep)) / + (4. * (**mInductance) * (**mCapacitance) + + 2. * timeStep * (**mResistance) * (**mCapacitance) + + (timeStep * timeStep)))); + //State Equation two: bottom left entry + mDufourAKHat(1, 0) = -((4. * (**mCapacitance) * timeStep) / + (4. * (**mInductance) * (**mCapacitance) + + 2. * timeStep * (**mCapacitance) * (**mResistance) + + (timeStep * timeStep))); + //State Equation two: bottom right entry + mDufourAKHat(1, 1) = (4. * (**mInductance) * (**mCapacitance) - + 2. * timeStep * (**mResistance) * (**mCapacitance) - + (timeStep * timeStep)) / + (4. * (**mInductance) * (**mCapacitance) + + 2. * timeStep * (**mResistance) * (**mCapacitance) + + (timeStep * timeStep)); + + ///Fill mDufourBKHat + //State Equation one: top entry + mDufourBKHat(0, 0) = (timeStep * timeStep) / + (4. * (**mInductance) * (**mCapacitance) + + 2. * timeStep * (**mCapacitance) * (**mResistance) + + (timeStep * timeStep)); + + //State Equation two: bottom entry + mDufourBKHat(1, 0) = (timeStep * 2. * (**mCapacitance)) / + (4. * (**mInductance) * (**mCapacitance) + + 2. * timeStep * (**mCapacitance) * (**mResistance) + + (timeStep * timeStep)); + + mDufourBKNHat = mDufourBKHat; + + mDufourCKN(0, 1) = 1.; + + mDufourWKN = (mDufourCKN * mDufourBKHat)(0, 0); + + mState(1, 0) = (**mIntfCurrent)(0, 0); + ssnUpdateState(); + mState(1, 0) = (**mIntfCurrent)(0, 0); + + **mRightVector = Matrix::Zero(leftVector->get().rows(), 1); + + SPDLOG_LOGGER_INFO(mSLog, + "\n--- MNA initialization ---" + "\nInitial voltage {:s}" + "\nInitial current {:s}" + "\n--- MNA initialization finished ---", + Logger::matrixToString(**mIntfVoltage), + Logger::matrixToString(**mIntfCurrent)); + mSLog->flush(); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompApplySystemMatrixStamp( + SparseMatrixRow &systemMatrix) { + MNAStampUtils::stampConductance(mDufourWKN, systemMatrix, matrixNodeIndex(0), + matrixNodeIndex(1), terminalNotGrounded(0), + terminalNotGrounded(1), mSLog); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompApplyRightSideVectorStamp( + Matrix &rightVector) { + // Update history term + mYHistory = (mDufourCKN * + (mDufourAKHat * mState + mDufourBKHat * **mIntfVoltage))(0, 0); + + if (terminalNotGrounded(0)) { + Math::setVectorElement(rightVector, matrixNodeIndex(0, 0), mYHistory); + } + if (terminalNotGrounded(1)) { + Math::setVectorElement(rightVector, matrixNodeIndex(1, 0), -mYHistory); + } + SPDLOG_LOGGER_DEBUG( + mSLog, "\nHistory current term (mnaCompApplyRightSideVectorStamp): {:s}", + Logger::matrixToString(mYHistory)); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { + // actually depends on L,C, but then we'd have to modify the system matrix anyway + prevStepDependencies.push_back(mIntfVoltage); + prevStepDependencies.push_back(mIntfCurrent); + modifiedAttributes.push_back(mRightVector); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompPreStep(Real time, + Int timeStepCount) { + mnaCompApplyRightSideVectorStamp(**mRightVector); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { + attributeDependencies.push_back(leftVector); + modifiedAttributes.push_back(mIntfVoltage); + modifiedAttributes.push_back(mIntfCurrent); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompPostStep( + Real time, Int timeStepCount, Attribute::Ptr &leftVector) { + mnaCompUpdateVoltage(**leftVector); + mnaCompUpdateCurrent(**leftVector); + ssnUpdateState(); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompUpdateVoltage( + const Matrix &leftVector) { + // v1 - v0 + mDufourUNT = (**mIntfVoltage)(0, 0); + **mIntfVoltage = Matrix::Zero(1, 1); + if (terminalNotGrounded(1)) { + (**mIntfVoltage)(0, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 0)); + } + if (terminalNotGrounded(0)) { + (**mIntfVoltage)(0, 0) = + (**mIntfVoltage)(0, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0)); + } + SPDLOG_LOGGER_DEBUG(mSLog, "\nUpdate Voltage: {:s}", + Logger::matrixToString(**mIntfVoltage)); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::mnaCompUpdateCurrent( + const Matrix &leftVector) { + (**mIntfCurrent)(0, 0) = mYHistory + (mDufourWKN * **mIntfVoltage)(0, 0); + + SPDLOG_LOGGER_DEBUG(mSLog, "\nUpdate Current: {:s}", + Logger::matrixToString(**mIntfCurrent)); +} + +void EMT::Ph1::SSN::Full_Serial_RLC::setParameters(Real resistance, + Real inductance, + Real capacitance) { + **mInductance = inductance; + **mCapacitance = capacitance; + **mResistance = resistance; + mParametersSet = true; +} + +void EMT::Ph1::SSN::Full_Serial_RLC::ssnUpdateState() { + mState = mDufourAKHat * mState + mDufourBKHat * mDufourUNT + + mDufourBKNHat * **mIntfVoltage; +} diff --git a/dpsim-models/src/EMT/EMT_Ph1_Switch.cpp b/dpsim-models/src/EMT/EMT_Ph1_Switch.cpp index 67221aa6bc..28679afd6f 100644 --- a/dpsim-models/src/EMT/EMT_Ph1_Switch.cpp +++ b/dpsim-models/src/EMT/EMT_Ph1_Switch.cpp @@ -29,7 +29,8 @@ void EMT::Ph1::Switch::initializeFromNodesAndTerminals(Real frequency) { Real resistance = (**mIsClosed) ? **mClosedResistance : **mOpenResistance; (**mIntfVoltage)(0, 0) = - RMS3PH_TO_PEAK1PH * (initialSingleVoltage(1) - initialSingleVoltage(0)).real(); + RMS3PH_TO_PEAK1PH * + (initialSingleVoltage(1) - initialSingleVoltage(0)).real(); (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / resistance; SPDLOG_LOGGER_INFO(mSLog, @@ -41,8 +42,10 @@ void EMT::Ph1::Switch::initializeFromNodesAndTerminals(Real frequency) { "\n--- Initialization from powerflow finished ---", Logger::matrixToString(**mIntfVoltage), Logger::matrixToString(**mIntfCurrent), - Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(0).real()), - Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(1).real())); + Logger::phasorToString(RMS3PH_TO_PEAK1PH * + initialSingleVoltage(0).real()), + Logger::phasorToString(RMS3PH_TO_PEAK1PH * + initialSingleVoltage(1).real())); } void EMT::Ph1::Switch::mnaCompInitialize(Real omega, Real timeStep, @@ -113,4 +116,14 @@ void EMT::Ph1::Switch::mnaCompUpdateCurrent(const Matrix &leftVector) { (**mIntfCurrent)(0, 0) = (**mIsClosed) ? (**mIntfVoltage)(0, 0) / (**mClosedResistance) : (**mIntfVoltage)(0, 0) / (**mOpenResistance); -} \ No newline at end of file +} + +Bool EMT::Ph1::Switch::hasParameterChanged() { + // Check if state of switch changed + if (!(mIsClosedPrev == this->mnaIsClosed())) { + mIsClosedPrev = this->mnaIsClosed(); + return 1; //recompute system matrix + } else { + return 0; // do not recompute system matrix + } +}; diff --git a/dpsim-models/src/EMT/EMT_Ph1_VoltageSource.cpp b/dpsim-models/src/EMT/EMT_Ph1_VoltageSource.cpp index 41688a8137..bc546b2a85 100644 --- a/dpsim-models/src/EMT/EMT_Ph1_VoltageSource.cpp +++ b/dpsim-models/src/EMT/EMT_Ph1_VoltageSource.cpp @@ -84,7 +84,7 @@ void EMT::Ph1::VoltageSource::updateVoltage(Real time) { if (srcFreq > 0) (**mIntfVoltage)(0, 0) = Math::abs(voltageRef) * - cos((time)*2. * PI * srcFreq + Math::phase(voltageRef)); + cos((time) * 2. * PI * srcFreq + Math::phase(voltageRef)); else (**mIntfVoltage)(0, 0) = voltageRef.real(); } diff --git a/dpsim-models/src/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.cpp b/dpsim-models/src/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.cpp index c6bc96ff2b..185ba8aa11 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_AvVoltSourceInverterStateSpace.cpp @@ -10,8 +10,8 @@ using namespace CPS; -// !!! TODO: Adaptions to use in EMT_Ph3 models phase-to-ground peak variables -// !!! with initialization from phase-to-phase RMS variables +// !!! TODO: Adaptions to use in EMT_Ph3 models phase-to-ground peak variables +// !!! with initialization from phase-to-phase RMS variables EMT::Ph3::AvVoltSourceInverterStateSpace::AvVoltSourceInverterStateSpace( String uid, String name, Logger::Level logLevel) @@ -148,12 +148,6 @@ void EMT::Ph3::AvVoltSourceInverterStateSpace::initializeStates( **mGamma_q = 0.006339; **mVcabc = initVgabc; mIfabc = Matrix::Zero(3, 1); - /*mVca = initVcabc(0, 0); - mVcb = initVcabc(1, 0); - mVcc = initVcabc(2, 0); - mIfa = initIfabc(0, 0); - mIfb = initIfabc(1, 0); - mIfc = initIfabc(2, 0);*/ mStates << **mThetaPLL, **mPhiPLL, **mP, **mQ, **mPhi_d, **mPhi_q, **mGamma_d, **mGamma_q, **mVcabc, mIfabc; @@ -181,14 +175,6 @@ void EMT::Ph3::AvVoltSourceInverterStateSpace::updateStates() { **mGamma_d = newStates(7, 0); **mVcabc = newStates.block(8, 0, 3, 1); mIfabc = newStates.block(11, 0, 3, 1); - /* - mIfa = newStates(8, 1); - mIfb = newStates(9, 1); - mIfc = newStates(10, 1); - mVca = newStates(11, 1); - mVcb = newStates(12, 1); - mVcc = newStates(13, 1); -*/ mStates = newStates; mU = newU; @@ -220,10 +206,7 @@ void EMT::Ph3::AvVoltSourceInverterStateSpace::updateLinearizedCoeffs() { Tabc2 * mKiCurrCtrlq, Matrix::Zero(3, 3), -Tabc1 * mKpCurrCtrld * Td - Tabc2 * mKpCurrCtrlq * Tq; mA.block(11, 0, 3, 14) = A_bottom; - /* - will it be faster to reconstruct the full B matrix (14x5) - rather than doing three insertions? - */ + // Will it be faster to reconstruct the full B matrix (14x5) rather than doing three insertions? mB.block(2, 2, 1, 3) = 3. / 2. * mOmegaCutoff * (Td * mIg_abc * Td + Tq * mIg_abc * Tq); mB.block(3, 2, 1, 3) = diff --git a/dpsim-models/src/EMT/EMT_Ph3_ControlledCurrentSource.cpp b/dpsim-models/src/EMT/EMT_Ph3_ControlledCurrentSource.cpp index 35e7fa66ca..ddfb4a9251 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_ControlledCurrentSource.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_ControlledCurrentSource.cpp @@ -10,8 +10,10 @@ using namespace CPS; -EMT::Ph3::ControlledCurrentSource::ControlledCurrentSource(String uid, String name, Logger::Level logLevel) - : MNASimPowerComp(uid, name, true, true, logLevel), mCurrentRef(mAttributes->create("I_ref")) { +EMT::Ph3::ControlledCurrentSource::ControlledCurrentSource( + String uid, String name, Logger::Level logLevel) + : MNASimPowerComp(uid, name, true, true, logLevel), + mCurrentRef(mAttributes->create("I_ref")) { mPhaseType = PhaseType::ABC; setVirtualNodeNumber(0); setTerminalNumber(2); @@ -26,14 +28,15 @@ SimPowerComp::Ptr EMT::Ph3::ControlledCurrentSource::clone(String name) { void EMT::Ph3::ControlledCurrentSource::setParameters(Matrix currentRef) { **mCurrentRef = currentRef; - - mSLog->info("\nCurrent reference phasor [I]: {:s}", Logger::matrixCompToString(currentRef)); - + SPDLOG_LOGGER_INFO(mSLog, "\nCurrent reference phasor [I]: {:s}", + Logger::matrixCompToString(currentRef)); mParametersSet = true; } -void EMT::Ph3::ControlledCurrentSource::initializeFromNodesAndTerminals(Real frequency) { - SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialization from node voltages and terminal ---"); +void EMT::Ph3::ControlledCurrentSource::initializeFromNodesAndTerminals( + Real frequency) { + SPDLOG_LOGGER_INFO( + mSLog, "\n--- Initialization from node voltages and terminal ---"); if (!mParametersSet) { **mCurrentRef = Matrix::Zero(3, 1); @@ -42,70 +45,105 @@ void EMT::Ph3::ControlledCurrentSource::initializeFromNodesAndTerminals(Real fre "\nTerminal 1 voltage: {:s}" "\nTerminal 0 power: {:s}" "\nTerminal 1 power: {:s}", - Logger::phasorToString(initialSingleVoltage(0)), Logger::phasorToString(initialSingleVoltage(1)), Logger::complexToString(terminal(0)->singlePower()), + Logger::phasorToString(initialSingleVoltage(0)), + Logger::phasorToString(initialSingleVoltage(1)), + Logger::complexToString(terminal(0)->singlePower()), Logger::complexToString(terminal(1)->singlePower())); } else { - SPDLOG_LOGGER_INFO(mSLog, - "\nInitialization from node voltages and terminal omitted (parameter " - "already set)." - "\nReference voltage: {:s}", - Logger::matrixToString(attributeTyped("I_ref")->get())); + SPDLOG_LOGGER_INFO( + mSLog, + "\nInitialization from node voltages and terminal omitted (parameter " + "already set)." + "\nReference voltage: {:s}", + Logger::matrixToString(attributeTyped("I_ref")->get())); } - SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialization from node voltages and terminal ---"); + SPDLOG_LOGGER_INFO( + mSLog, "\n--- Initialization from node voltages and terminal ---"); mSLog->flush(); } -void EMT::Ph3::ControlledCurrentSource::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { updateMatrixNodeIndices(); } +void EMT::Ph3::ControlledCurrentSource::mnaCompInitialize( + Real omega, Real timeStep, Attribute::Ptr leftVector) { + updateMatrixNodeIndices(); +} -void EMT::Ph3::ControlledCurrentSource::mnaCompApplyRightSideVectorStamp(Matrix &rightVector) { +void EMT::Ph3::ControlledCurrentSource::mnaCompApplyRightSideVectorStamp( + Matrix &rightVector) { if (terminalNotGrounded(1)) { - Math::setVectorElement(rightVector, matrixNodeIndex(1, 0), -(**mIntfCurrent)(0, 0)); - Math::setVectorElement(rightVector, matrixNodeIndex(1, 1), -(**mIntfCurrent)(1, 0)); - Math::setVectorElement(rightVector, matrixNodeIndex(1, 2), -(**mIntfCurrent)(2, 0)); + Math::setVectorElement(rightVector, matrixNodeIndex(1, 0), + -(**mIntfCurrent)(0, 0)); + Math::setVectorElement(rightVector, matrixNodeIndex(1, 1), + -(**mIntfCurrent)(1, 0)); + Math::setVectorElement(rightVector, matrixNodeIndex(1, 2), + -(**mIntfCurrent)(2, 0)); } if (terminalNotGrounded(0)) { - Math::setVectorElement(rightVector, matrixNodeIndex(0, 0), (**mIntfCurrent)(0, 0)); - Math::setVectorElement(rightVector, matrixNodeIndex(0, 1), (**mIntfCurrent)(1, 0)); - Math::setVectorElement(rightVector, matrixNodeIndex(0, 2), (**mIntfCurrent)(2, 0)); + Math::setVectorElement(rightVector, matrixNodeIndex(0, 0), + (**mIntfCurrent)(0, 0)); + Math::setVectorElement(rightVector, matrixNodeIndex(0, 1), + (**mIntfCurrent)(1, 0)); + Math::setVectorElement(rightVector, matrixNodeIndex(0, 2), + (**mIntfCurrent)(2, 0)); } } void EMT::Ph3::ControlledCurrentSource::updateCurrent(Real time) { **mIntfCurrent = **mCurrentRef; - SPDLOG_LOGGER_DEBUG(mSLog, "\nUpdate current: {:s}", Logger::matrixToString(**mIntfCurrent)); + SPDLOG_LOGGER_DEBUG(mSLog, "\nUpdate current: {:s}", + Logger::matrixToString(**mIntfCurrent)); } -void EMT::Ph3::ControlledCurrentSource::mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) { +void EMT::Ph3::ControlledCurrentSource::mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { attributeDependencies.push_back(mCurrentRef); modifiedAttributes.push_back(mRightVector); modifiedAttributes.push_back(mIntfVoltage); } -void EMT::Ph3::ControlledCurrentSource::mnaCompPreStep(Real time, Int timeStepCount) { +void EMT::Ph3::ControlledCurrentSource::mnaCompPreStep(Real time, + Int timeStepCount) { updateCurrent(time); mnaCompApplyRightSideVectorStamp(**mRightVector); } -void EMT::Ph3::ControlledCurrentSource::mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector) { +void EMT::Ph3::ControlledCurrentSource::mnaCompAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { attributeDependencies.push_back(leftVector); modifiedAttributes.push_back(mIntfVoltage); }; -void EMT::Ph3::ControlledCurrentSource::mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) { mnaCompUpdateVoltage(**leftVector); } +void EMT::Ph3::ControlledCurrentSource::mnaCompPostStep( + Real time, Int timeStepCount, Attribute::Ptr &leftVector) { + mnaCompUpdateVoltage(**leftVector); +} -void EMT::Ph3::ControlledCurrentSource::mnaCompUpdateVoltage(const Matrix &leftVector) { +void EMT::Ph3::ControlledCurrentSource::mnaCompUpdateVoltage( + const Matrix &leftVector) { // v1 - v0 **mIntfVoltage = Matrix::Zero(3, 1); if (terminalNotGrounded(1)) { - (**mIntfVoltage)(0, 0) = Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 0)); - (**mIntfVoltage)(1, 0) = Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 1)); - (**mIntfVoltage)(2, 0) = Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 2)); + (**mIntfVoltage)(0, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 0)); + (**mIntfVoltage)(1, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 1)); + (**mIntfVoltage)(2, 0) = + Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 2)); } if (terminalNotGrounded(0)) { - (**mIntfVoltage)(0, 0) = (**mIntfVoltage)(0, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0)); - (**mIntfVoltage)(1, 0) = (**mIntfVoltage)(1, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 1)); - (**mIntfVoltage)(2, 0) = (**mIntfVoltage)(2, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2)); + (**mIntfVoltage)(0, 0) = + (**mIntfVoltage)(0, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0)); + (**mIntfVoltage)(1, 0) = + (**mIntfVoltage)(1, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 1)); + (**mIntfVoltage)(2, 0) = + (**mIntfVoltage)(2, 0) - + Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2)); } } diff --git a/dpsim-models/src/EMT/EMT_Ph3_ControlledVoltageSource.cpp b/dpsim-models/src/EMT/EMT_Ph3_ControlledVoltageSource.cpp index c93620a3b5..0dd96f9970 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_ControlledVoltageSource.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_ControlledVoltageSource.cpp @@ -10,8 +10,11 @@ using namespace CPS; -EMT::Ph3::ControlledVoltageSource::ControlledVoltageSource(String uid, String name, Logger::Level logLevel) - : MNASimPowerComp(uid, name, true, true, logLevel), mVoltageRef(mAttributes->createDynamic("V_ref")) // rms-value, phase-to-phase +EMT::Ph3::ControlledVoltageSource::ControlledVoltageSource( + String uid, String name, Logger::Level logLevel) + : MNASimPowerComp(uid, name, true, true, logLevel), + mVoltageRef(mAttributes->createDynamic( + "V_ref")) // rms-value, phase-to-phase { mPhaseType = PhaseType::ABC; setVirtualNodeNumber(1); @@ -26,7 +29,8 @@ void EMT::Ph3::ControlledVoltageSource::setParameters(Matrix voltageRef) { mParametersSet = true; } -void EMT::Ph3::ControlledVoltageSource::initializeFromNodesAndTerminals(Real frequency) { +void EMT::Ph3::ControlledVoltageSource::initializeFromNodesAndTerminals( + Real frequency) { SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialization from node voltages ---"); // TODO: this approach currently overwrites voltage reference set from outside, when not using setParameters if (!mParametersSet) { @@ -35,12 +39,15 @@ void EMT::Ph3::ControlledVoltageSource::initializeFromNodesAndTerminals(Real fre "\nReference voltage: {:s}" "\nTerminal 0 voltage: {:s}" "\nTerminal 1 voltage: {:s}", - Logger::matrixCompToString(**mVoltageRef), Logger::phasorToString(initialSingleVoltage(0)), Logger::phasorToString(initialSingleVoltage(1))); + Logger::matrixCompToString(**mVoltageRef), + Logger::phasorToString(initialSingleVoltage(0)), + Logger::phasorToString(initialSingleVoltage(1))); } else { - SPDLOG_LOGGER_INFO(mSLog, - "\nInitialization from node voltages omitted (parameter already set)." - "\nReference voltage: {:s}", - Logger::matrixCompToString(**mVoltageRef)); + SPDLOG_LOGGER_INFO( + mSLog, + "\nInitialization from node voltages omitted (parameter already set)." + "\nReference voltage: {:s}", + Logger::matrixCompToString(**mVoltageRef)); } SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialization from node voltages ---"); mSLog->flush(); @@ -52,64 +59,114 @@ SimPowerComp::Ptr EMT::Ph3::ControlledVoltageSource::clone(String name) { return copy; } -void EMT::Ph3::ControlledVoltageSource::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { updateMatrixNodeIndices(); } +void EMT::Ph3::ControlledVoltageSource::mnaCompInitialize( + Real omega, Real timeStep, Attribute::Ptr leftVector) { + updateMatrixNodeIndices(); +} -void EMT::Ph3::ControlledVoltageSource::mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) { +void EMT::Ph3::ControlledVoltageSource::mnaCompApplySystemMatrixStamp( + SparseMatrixRow &systemMatrix) { if (terminalNotGrounded(0)) { - Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 0), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), -1); - Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(0, 0), -1); - - Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 1), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), -1); - Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(0, 1), -1); - - Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 2), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), -1); - Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(0, 2), -1); + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 0), + mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), + -1); + Math::addToMatrixElement(systemMatrix, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), + matrixNodeIndex(0, 0), -1); + + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 1), + mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), + -1); + Math::addToMatrixElement(systemMatrix, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), + matrixNodeIndex(0, 1), -1); + + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 2), + mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), + -1); + Math::addToMatrixElement(systemMatrix, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), + matrixNodeIndex(0, 2), -1); } if (terminalNotGrounded(1)) { - Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 0), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), 1); - Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(1, 0), 1); - - Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 1), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), 1); - Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(1, 1), 1); - - Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 2), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), 1); - Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(1, 2), 1); + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 0), + mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), + 1); + Math::addToMatrixElement(systemMatrix, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), + matrixNodeIndex(1, 0), 1); + + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 1), + mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), + 1); + Math::addToMatrixElement(systemMatrix, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), + matrixNodeIndex(1, 1), 1); + + Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 2), + mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), + 1); + Math::addToMatrixElement(systemMatrix, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), + matrixNodeIndex(1, 2), 1); } } -void EMT::Ph3::ControlledVoltageSource::mnaCompApplyRightSideVectorStamp(Matrix &rightVector) { - Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), (**mIntfVoltage)(0, 0)); - Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), (**mIntfVoltage)(1, 0)); - Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), (**mIntfVoltage)(2, 0)); +void EMT::Ph3::ControlledVoltageSource::mnaCompApplyRightSideVectorStamp( + Matrix &rightVector) { + Math::setVectorElement(rightVector, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), + (**mIntfVoltage)(0, 0)); + Math::setVectorElement(rightVector, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), + (**mIntfVoltage)(1, 0)); + Math::setVectorElement(rightVector, + mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), + (**mIntfVoltage)(2, 0)); } void EMT::Ph3::ControlledVoltageSource::updateVoltage(Real time) { **mIntfVoltage = **mVoltageRef; - SPDLOG_LOGGER_DEBUG(mSLog, "\nUpdate Voltage: {:s}", Logger::matrixToString(**mIntfVoltage)); + SPDLOG_LOGGER_DEBUG(mSLog, "\nUpdate Voltage: {:s}", + Logger::matrixToString(**mIntfVoltage)); } -void EMT::Ph3::ControlledVoltageSource::mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) { +void EMT::Ph3::ControlledVoltageSource::mnaCompAddPreStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes) { attributeDependencies.push_back(mVoltageRef); modifiedAttributes.push_back(mRightVector); modifiedAttributes.push_back(mIntfVoltage); } -void EMT::Ph3::ControlledVoltageSource::mnaCompPreStep(Real time, Int timeStepCount) { +void EMT::Ph3::ControlledVoltageSource::mnaCompPreStep(Real time, + Int timeStepCount) { updateVoltage(time); mnaCompApplyRightSideVectorStamp(**mRightVector); } -void EMT::Ph3::ControlledVoltageSource::mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, - Attribute::Ptr &leftVector) { +void EMT::Ph3::ControlledVoltageSource::mnaCompAddPostStepDependencies( + AttributeBase::List &prevStepDependencies, + AttributeBase::List &attributeDependencies, + AttributeBase::List &modifiedAttributes, + Attribute::Ptr &leftVector) { attributeDependencies.push_back(leftVector); modifiedAttributes.push_back(mIntfCurrent); }; -void EMT::Ph3::ControlledVoltageSource::mnaCompPostStep(Real time, Int timeStepCount, Attribute::Ptr &leftVector) { mnaCompUpdateCurrent(**leftVector); } +void EMT::Ph3::ControlledVoltageSource::mnaCompPostStep( + Real time, Int timeStepCount, Attribute::Ptr &leftVector) { + mnaCompUpdateCurrent(**leftVector); +} -void EMT::Ph3::ControlledVoltageSource::mnaCompUpdateCurrent(const Matrix &leftVector) { - (**mIntfCurrent)(0, 0) = Math::realFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A)); - (**mIntfCurrent)(1, 0) = Math::realFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B)); - (**mIntfCurrent)(2, 0) = Math::realFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C)); +void EMT::Ph3::ControlledVoltageSource::mnaCompUpdateCurrent( + const Matrix &leftVector) { + (**mIntfCurrent)(0, 0) = Math::realFromVectorElement( + leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A)); + (**mIntfCurrent)(1, 0) = Math::realFromVectorElement( + leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B)); + (**mIntfCurrent)(2, 0) = Math::realFromVectorElement( + leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C)); } diff --git a/dpsim-models/src/EMT/EMT_Ph3_CurrentSource.cpp b/dpsim-models/src/EMT/EMT_Ph3_CurrentSource.cpp index a2aab0319a..a3dfbdb5b9 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_CurrentSource.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_CurrentSource.cpp @@ -39,10 +39,11 @@ void EMT::Ph3::CurrentSource::setParameters(MatrixComp currentRef, **mCurrentRef = currentRef; mSrcFreq->setReference(mSrcSig->mFreq); - mSLog->info("\nCurrent reference phasor [I]: {:s}" - "\nFrequency [Hz]: {:s}", - Logger::matrixCompToString(currentRef), - Logger::realToString(srcFreq)); + SPDLOG_LOGGER_INFO(mSLog, + "\nCurrent reference phasor [I]: {:s}" + "\nFrequency [Hz]: {:s}", + Logger::matrixCompToString(currentRef), + Logger::realToString(srcFreq)); mParametersSet = true; } @@ -184,4 +185,4 @@ void EMT::Ph3::CurrentSource::mnaCompUpdateVoltage(const Matrix &leftVector) { (**mIntfVoltage)(2, 0) - Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2)); } -} \ No newline at end of file +} diff --git a/dpsim-models/src/EMT/EMT_Ph3_Inductor.cpp b/dpsim-models/src/EMT/EMT_Ph3_Inductor.cpp index be7b68b3ec..cb1d3e7a96 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_Inductor.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_Inductor.cpp @@ -185,3 +185,38 @@ void EMT::Ph3::Inductor::mnaCompUpdateCurrent(const Matrix &leftVector) { Logger::matrixToString(**mIntfCurrent)); mSLog->flush(); } + +// #### Tear Methods #### +void EMT::Ph3::Inductor::mnaTearInitialize(Real omega, Real timeStep) { + //initVars(omega, timeStep); + updateMatrixNodeIndices(); + mEquivCond = timeStep / 2. * (**mInductance).inverse(); + // Update internal state + mEquivCurrent = mEquivCond * **mIntfVoltage + **mIntfCurrent; +} + +void EMT::Ph3::Inductor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + // Set diagonal entries + Math::addToMatrixElement(tearMatrix, mTearIdx * 3, mTearIdx * 3, + 1. / mEquivCond(0, 0)); // 1 / + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 1, mTearIdx * 3 + 1, + 1. / mEquivCond(1, 1)); + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 2, mTearIdx * 3 + 2, + 1. / mEquivCond(2, 2)); +} + +void EMT::Ph3::Inductor::mnaTearApplyVoltageStamp(Matrix &voltageVector) { + mEquivCurrent = mEquivCond * **mIntfVoltage + **mIntfCurrent; + Math::addToVectorElement(voltageVector, mTearIdx * 3, + mEquivCurrent(0, 0) / mEquivCond(0, 0)); + Math::addToVectorElement(voltageVector, mTearIdx * 3 + 1, + mEquivCurrent(1, 0) / mEquivCond(1, 1)); + Math::addToVectorElement(voltageVector, mTearIdx * 3 + 2, + mEquivCurrent(2, 0) / mEquivCond(2, 2)); +} + +void EMT::Ph3::Inductor::mnaTearPostStep(MatrixComp voltage, + MatrixComp current) { + (**mIntfVoltage) = voltage.real(); + (**mIntfCurrent) = (mEquivCond * voltage).real() + mEquivCurrent; +} diff --git a/dpsim-models/src/EMT/EMT_Ph3_PiLine.cpp b/dpsim-models/src/EMT/EMT_Ph3_PiLine.cpp index 3fef318e8a..18ff43c39d 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_PiLine.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_PiLine.cpp @@ -227,3 +227,40 @@ void EMT::Ph3::PiLine::mnaCompUpdateVoltage(const Matrix &leftVector) { void EMT::Ph3::PiLine::mnaCompUpdateCurrent(const Matrix &leftVector) { **mIntfCurrent = mSubSeriesInductor->intfCurrent(); } + +// #### Tear Methods #### +MNAInterface::List EMT::Ph3::PiLine::mnaTearGroundComponents() { + MNAInterface::List gndComponents; + + gndComponents.push_back(mSubParallelResistor0); + gndComponents.push_back(mSubParallelResistor1); + + if ((**mParallelCap)(0, 0) > 0) { + gndComponents.push_back(mSubParallelCapacitor0); + gndComponents.push_back(mSubParallelCapacitor1); + } + + return gndComponents; +} + +void EMT::Ph3::PiLine::mnaTearInitialize(Real omega, Real timeStep) { + mSubSeriesResistor->mnaTearSetIdx(mTearIdx); + mSubSeriesResistor->mnaTearInitialize(omega, timeStep); + mSubSeriesInductor->mnaTearSetIdx(mTearIdx); + mSubSeriesInductor->mnaTearInitialize(omega, timeStep); +} + +void EMT::Ph3::PiLine::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + mSubSeriesResistor->mnaTearApplyMatrixStamp(tearMatrix); + mSubSeriesInductor->mnaTearApplyMatrixStamp(tearMatrix); +} + +void EMT::Ph3::PiLine::mnaTearApplyVoltageStamp(Matrix &voltageVector) { + mSubSeriesInductor->mnaTearApplyVoltageStamp(voltageVector); +} + +void EMT::Ph3::PiLine::mnaTearPostStep(MatrixComp voltage, MatrixComp current) { + mSubSeriesInductor->mnaTearPostStep(voltage - (**mSeriesRes * current), + current); + (**mIntfCurrent) = mSubSeriesInductor->intfCurrent(); +} diff --git a/dpsim-models/src/EMT/EMT_Ph3_RXLoad.cpp b/dpsim-models/src/EMT/EMT_Ph3_RXLoad.cpp index c412e7f3f5..56dc11431b 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_RXLoad.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_RXLoad.cpp @@ -11,8 +11,11 @@ using namespace CPS; EMT::Ph3::RXLoad::RXLoad(String uid, String name, Logger::Level logLevel) - : CompositePowerComp(uid, name, true, true, Logger::Level::trace), mActivePower(mAttributes->create("P")), mReactivePower(mAttributes->create("Q")), - mNomVoltage(mAttributes->create("V_nom")), mReactanceInSeries(false) { + : CompositePowerComp(uid, name, true, true, Logger::Level::trace), + mActivePower(mAttributes->create("P")), + mReactivePower(mAttributes->create("Q")), + mNomVoltage(mAttributes->create("V_nom")), + mReactanceInSeries(false) { mPhaseType = PhaseType::ABC; setTerminalNumber(1); @@ -45,7 +48,8 @@ EMT::Ph3::RXLoad::RXLoad(String name, Matrix activePower, Matrix reactivePower, initPowerFromTerminal = false; } -void EMT::Ph3::RXLoad::setParameters(Matrix activePower, Matrix reactivePower, Real volt, bool reactanceInSeries) { +void EMT::Ph3::RXLoad::setParameters(Matrix activePower, Matrix reactivePower, + Real volt, bool reactanceInSeries) { **mActivePower = activePower; **mReactivePower = reactivePower; mReactanceInSeries = reactanceInSeries; @@ -107,18 +111,26 @@ void EMT::Ph3::RXLoad::initializeFromNodesAndTerminals(Real frequency) { **mIntfVoltage = vInitABC.real(); if ((**mActivePower)(0, 0) != 0) { - mResistance = std::pow(**mNomVoltage / sqrt(3), 2) * (**mActivePower).inverse(); + mResistance = + std::pow(**mNomVoltage / sqrt(3), 2) * (**mActivePower).inverse(); } if ((**mReactivePower)(0, 0) != 0) - mReactance = std::pow(**mNomVoltage / sqrt(3), 2) * (**mReactivePower).inverse(); + mReactance = + std::pow(**mNomVoltage / sqrt(3), 2) * (**mReactivePower).inverse(); else mReactance = Matrix::Zero(1, 1); if (mReactanceInSeries) { MatrixComp impedance = MatrixComp::Zero(3, 3); - impedance << Complex(mResistance(0, 0), mReactance(0, 0)), Complex(mResistance(0, 1), mReactance(0, 1)), Complex(mResistance(0, 2), mReactance(0, 2)), Complex(mResistance(1, 0), mReactance(1, 0)), - Complex(mResistance(1, 1), mReactance(1, 1)), Complex(mResistance(1, 2), mReactance(1, 2)), Complex(mResistance(2, 0), mReactance(2, 0)), Complex(mResistance(2, 1), mReactance(2, 1)), + impedance << Complex(mResistance(0, 0), mReactance(0, 0)), + Complex(mResistance(0, 1), mReactance(0, 1)), + Complex(mResistance(0, 2), mReactance(0, 2)), + Complex(mResistance(1, 0), mReactance(1, 0)), + Complex(mResistance(1, 1), mReactance(1, 1)), + Complex(mResistance(1, 2), mReactance(1, 2)), + Complex(mResistance(2, 0), mReactance(2, 0)), + Complex(mResistance(2, 1), mReactance(2, 1)), Complex(mResistance(2, 2), mReactance(2, 2)); **mIntfCurrent = (impedance.inverse() * vInitABC).real(); @@ -128,11 +140,13 @@ void EMT::Ph3::RXLoad::initializeFromNodesAndTerminals(Real frequency) { vInitTerm0(0, 0) = initialSingleVoltage(0); vInitTerm0(1, 0) = vInitTerm0(0, 0) * SHIFT_TO_PHASE_B; vInitTerm0(2, 0) = vInitTerm0(0, 0) * SHIFT_TO_PHASE_C; - mVirtualNodes[0]->setInitialVoltage(vInitTerm0 + mResistance * **mIntfCurrent); + mVirtualNodes[0]->setInitialVoltage(vInitTerm0 + + mResistance * **mIntfCurrent); } if ((**mActivePower)(0, 0) != 0) { - mSubResistor = std::make_shared(**mName + "_res", mLogLevel); + mSubResistor = + std::make_shared(**mName + "_res", mLogLevel); mSubResistor->setParameters(mResistance); if (mReactanceInSeries) { mSubResistor->connect({mTerminals[0]->node(), mVirtualNodes[0]}); @@ -141,7 +155,8 @@ void EMT::Ph3::RXLoad::initializeFromNodesAndTerminals(Real frequency) { } mSubResistor->initialize(mFrequencies); mSubResistor->initializeFromNodesAndTerminals(frequency); - addMNASubComponent(mSubResistor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); + addMNASubComponent(mSubResistor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, + MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); if (!mReactanceInSeries) { **mIntfCurrent += mSubResistor->intfCurrent(); @@ -155,9 +170,9 @@ void EMT::Ph3::RXLoad::initializeFromNodesAndTerminals(Real frequency) { std::make_shared(**mName + "_ind", mLogLevel); mSubInductor->setParameters(mInductance); if (mReactanceInSeries) { - mSubInductor->connect({SimNode::GND, mVirtualNodes[0]}); + mSubInductor->connect({SimNode::GND, mVirtualNodes[0]}); } else { - mSubInductor->connect({SimNode::GND, mTerminals[0]->node()}); + mSubInductor->connect({SimNode::GND, mTerminals[0]->node()}); } mSubInductor->initialize(mFrequencies); mSubInductor->initializeFromNodesAndTerminals(frequency); diff --git a/dpsim-models/src/EMT/EMT_Ph3_Resistor.cpp b/dpsim-models/src/EMT/EMT_Ph3_Resistor.cpp index 88ce5229de..dfd97dc427 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_Resistor.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_Resistor.cpp @@ -131,3 +131,16 @@ void EMT::Ph3::Resistor::mnaCompUpdateCurrent(const Matrix &leftVector) { Logger::matrixToString(**mIntfCurrent)); mSLog->flush(); } + +// #### Tear Methods #### +void EMT::Ph3::Resistor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) { + MatrixFixedSizeComp<3, 3> conductance = Matrix::Zero(3, 3); + conductance.real() = (**mResistance).inverse(); + // Set diagonal entries + Math::addToMatrixElement(tearMatrix, mTearIdx * 3, mTearIdx * 3, + 1. / conductance(0, 0).real()); + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 1, mTearIdx * 3 + 1, + 1. / conductance(1, 1).real()); + Math::addToMatrixElement(tearMatrix, mTearIdx * 3 + 2, mTearIdx * 3 + 2, + 1. / conductance(2, 2).real()); +} diff --git a/dpsim-models/src/EMT/EMT_Ph3_SSN_Full_Serial_RLC.cpp b/dpsim-models/src/EMT/EMT_Ph3_SSN_Full_Serial_RLC.cpp index 1b53bb2a77..52440aadef 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_SSN_Full_Serial_RLC.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_SSN_Full_Serial_RLC.cpp @@ -359,4 +359,4 @@ void EMT::Ph3::SSN::Full_Serial_RLC::setParameters(Matrix resistance, void EMT::Ph3::SSN::Full_Serial_RLC::ssnUpdateState() { mState = mDufourAKHat * mState + mDufourBKHat * mDufourUNT + mDufourBKNHat * **mIntfVoltage; -} \ No newline at end of file +} diff --git a/dpsim-models/src/EMT/EMT_Ph3_SeriesSwitch.cpp b/dpsim-models/src/EMT/EMT_Ph3_SeriesSwitch.cpp index 7a75c76950..18ae441270 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_SeriesSwitch.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_SeriesSwitch.cpp @@ -128,3 +128,13 @@ void EMT::Ph3::SeriesSwitch::mnaCompUpdateCurrent(const Matrix &leftVector) { SPDLOG_LOGGER_DEBUG(mSLog, "Current A: {}", (**mIntfCurrent)(0, 0)); } + +Bool EMT::Ph3::SeriesSwitch::hasParameterChanged() { + // Check if state of switch changed + if (!(mIsClosedPrev == this->mnaIsClosed())) { + mIsClosedPrev = this->mnaIsClosed(); + return 1; //recompute system matrix + } else { + return 0; // do not recompute system matrix + } +}; diff --git a/dpsim-models/src/EMT/EMT_Ph3_Switch.cpp b/dpsim-models/src/EMT/EMT_Ph3_Switch.cpp index 8eeb521d27..c4dc5a44a6 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_Switch.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_Switch.cpp @@ -23,14 +23,13 @@ EMT::Ph3::Switch::Switch(String uid, String name, Logger::Level logLevel) SimPowerComp::Ptr EMT::Ph3::Switch::clone(String name) { auto copy = Switch::make(name, mLogLevel); - copy->setParameters(**mOpenResistance, **mClosedResistance, **mSwitchClosed); + copy->setParameters(**mOpenResistance, **mClosedResistance, **mIsClosed); return copy; } void EMT::Ph3::Switch::initializeFromNodesAndTerminals(Real frequency) { - Matrix impedance = - (**mSwitchClosed) ? **mClosedResistance : **mOpenResistance; + Matrix impedance = (**mIsClosed) ? **mClosedResistance : **mOpenResistance; MatrixComp vInitABC = MatrixComp::Zero(3, 1); vInitABC(0, 0) = initialSingleVoltage(1) - initialSingleVoltage(0); vInitABC(1, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_B; @@ -57,11 +56,11 @@ void EMT::Ph3::Switch::mnaCompInitialize(Real omega, Real timeStep, **mRightVector = Matrix::Zero(0, 0); } -Bool EMT::Ph3::Switch::mnaIsClosed() { return **mSwitchClosed; } +Bool EMT::Ph3::Switch::mnaIsClosed() { return **mIsClosed; } void EMT::Ph3::Switch::mnaCompApplySystemMatrixStamp( SparseMatrixRow &systemMatrix) { - MatrixFixedSize<3, 3> conductance = (**mSwitchClosed) + MatrixFixedSize<3, 3> conductance = (**mIsClosed) ? (**mClosedResistance).inverse() : (**mOpenResistance).inverse(); @@ -130,8 +129,18 @@ void EMT::Ph3::Switch::mnaCompUpdateVoltage(const Matrix &leftVector) { void EMT::Ph3::Switch::mnaCompUpdateCurrent(const Matrix &leftVector) { Matrix conductance = Matrix::Zero(3, 3); - (**mSwitchClosed) ? Math::invertMatrix(**mClosedResistance, conductance) - : Math::invertMatrix(**mOpenResistance, conductance); + (**mIsClosed) ? Math::invertMatrix(**mClosedResistance, conductance) + : Math::invertMatrix(**mOpenResistance, conductance); **mIntfCurrent = conductance * **mIntfVoltage; } + +Bool EMT::Ph3::Switch::hasParameterChanged() { + // Check if state of switch changed + if (!(mIsClosedPrev == this->mnaIsClosed())) { + mIsClosedPrev = this->mnaIsClosed(); + return 1; //recompute system matrix + } else { + return 0; // do not recompute system matrix + } +}; diff --git a/dpsim-models/src/EMT/EMT_Ph3_SynchronGeneratorDQODE.cpp b/dpsim-models/src/EMT/EMT_Ph3_SynchronGeneratorDQODE.cpp index 897b5295b8..d172ef2dab 100644 --- a/dpsim-models/src/EMT/EMT_Ph3_SynchronGeneratorDQODE.cpp +++ b/dpsim-models/src/EMT/EMT_Ph3_SynchronGeneratorDQODE.cpp @@ -10,8 +10,8 @@ using namespace CPS; -// !!! TODO: Adaptions to use in EMT_Ph3 models phase-to-ground peak variables -// !!! with initialization from phase-to-phase RMS variables +// !!! TODO: Adaptions to use in EMT_Ph3 models phase-to-ground peak variables +// !!! with initialization from phase-to-phase RMS variables EMT::Ph3::SynchronGeneratorDQODE::SynchronGeneratorDQODE(String uid, String name, @@ -118,8 +118,8 @@ void EMT::Ph3::SynchronGeneratorDQODE::odeStateSpace(double t, const double y[], ydot[mDim - 2] = y[mDim - 1] * mBase_OmMech; /* Auxiliary variables to compute - * T_e= lambda_d * i_q - lambda_q * i_d - * needed for omega: */ + * T_e= lambda_d * i_q - lambda_q * i_d + * needed for omega: */ realtype i_d = 0, i_q = 0; // Compute new currents (depending on updated fluxes) for (int i = 0; i < mDim - 2; i++) { diff --git a/dpsim-models/src/MathUtils.cpp b/dpsim-models/src/MathUtils.cpp index 4439464f3d..57972930b6 100644 --- a/dpsim-models/src/MathUtils.cpp +++ b/dpsim-models/src/MathUtils.cpp @@ -338,6 +338,21 @@ void Math::calculateStateSpaceTrapezoidalMatrices(const Matrix &A, Cd = F2inv * dt * C; } +void Math::calculateStateSpaceTrapezoidalMatrices(const Matrix &A, + const Matrix &B, + const Real &dt, Matrix &Ad, + Matrix &Bd) { + Matrix::Index n = A.rows(); + Matrix I = Matrix::Identity(n, n); + + Matrix F1 = I + (dt / 2.) * A; + Matrix F2 = I - (dt / 2.) * A; + Matrix F2inv = F2.inverse(); + + Ad = F2inv * F1; + Bd = F2inv * (dt / 2.) * B; +} + Matrix Math::applyStateSpaceTrapezoidalMatrices(const Matrix &Ad, const Matrix &Bd, const Matrix &Cd, diff --git a/dpsim-models/src/SP/SP_Ph1_AvVoltageSourceInverterDQ.cpp b/dpsim-models/src/SP/SP_Ph1_AvVoltageSourceInverterDQ.cpp index cc0d5cf31b..653a5c2eea 100644 --- a/dpsim-models/src/SP/SP_Ph1_AvVoltageSourceInverterDQ.cpp +++ b/dpsim-models/src/SP/SP_Ph1_AvVoltageSourceInverterDQ.cpp @@ -14,7 +14,6 @@ SP::Ph1::AvVoltageSourceInverterDQ::AvVoltageSourceInverterDQ( String uid, String name, Logger::Level logLevel, Bool withTrafo) : CompositePowerComp(uid, name, true, true, logLevel), mOmegaN(mAttributes->create("Omega_nom")), - mVnom(mAttributes->create("vnom")), mPref(mAttributes->create("P_ref")), mQref(mAttributes->create("Q_ref")), mVcd(mAttributes->create("Vc_d", 0)), @@ -107,7 +106,7 @@ void SP::Ph1::AvVoltageSourceInverterDQ::setParameters(Real sysOmega, mPowerControllerVSI->setParameters(Pref, Qref); **mOmegaN = sysOmega; - **mVnom = sysVoltNom; + mVnom = sysVoltNom; **mPref = Pref; **mQref = Qref; } @@ -295,6 +294,8 @@ void SP::Ph1::AvVoltageSourceInverterDQ::initializeFromNodesAndTerminals( SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialization from powerflow finished ---"); } +Real SP::Ph1::AvVoltageSourceInverterDQ::getNomVoltage() const { return mVnom; } + void SP::Ph1::AvVoltageSourceInverterDQ::mnaParentInitialize( Real omega, Real timeStep, Attribute::Ptr leftVector) { mTimeStep = timeStep; diff --git a/dpsim-models/src/SP/SP_Ph1_Load.cpp b/dpsim-models/src/SP/SP_Ph1_Load.cpp index 8215d2cd25..4c25f2805e 100644 --- a/dpsim-models/src/SP/SP_Ph1_Load.cpp +++ b/dpsim-models/src/SP/SP_Ph1_Load.cpp @@ -20,9 +20,8 @@ SP::Ph1::Load::Load(String uid, String name, Logger::Level logLevel) mActivePower(mAttributes->createDynamic( "P")), //Made dynamic so it can be imported through InterfaceVillas mReactivePower(mAttributes->createDynamic( - "Q")), //Made dynamic so it can be imported through InterfaceVillas - mNomVoltage(mAttributes->create("V_nom")) { - + "Q")) //Made dynamic so it can be imported through InterfaceVillas +{ SPDLOG_LOGGER_INFO(mSLog, "Create {} of type {}", **mName, this->type()); mSLog->flush(); **mIntfVoltage = MatrixComp::Zero(1, 1); @@ -34,16 +33,20 @@ void SP::Ph1::Load::setParameters(Real activePower, Real reactivePower, Real nominalVoltage) { **mActivePower = activePower; **mReactivePower = reactivePower; - **mNomVoltage = nominalVoltage; + mNomVoltage = nominalVoltage; - SPDLOG_LOGGER_INFO(mSLog, "Active Power={} [W] Reactive Power={} [VAr]", - **mActivePower, **mReactivePower); + SPDLOG_LOGGER_INFO( + mSLog, + "Active Power={} [W] Reactive Power={} [VAr] Nominal Voltage={} [V]", + **mActivePower, **mReactivePower, mNomVoltage); mSLog->flush(); mParametersSet = true; } // #### Powerflow section #### +Real SP::Ph1::Load::getNomVoltage() const { return mNomVoltage; } + void SP::Ph1::Load::calculatePerUnitParameters(Real baseApparentPower, Real baseOmega) { SPDLOG_LOGGER_INFO(mSLog, "#### Calculate Per Unit Parameters for {}", @@ -105,7 +108,7 @@ void SP::Ph1::Load::initializeFromNodesAndTerminals(Real frequency) { // instantiate subResistor for active power consumption if (**mActivePower != 0) { - mResistance = std::pow(**mNomVoltage, 2) / **mActivePower; + mResistance = std::pow(mNomVoltage, 2) / **mActivePower; mConductance = 1.0 / mResistance; mSubResistor = std::make_shared( **mUID + "_res", **mName + "_res", Logger::Level::off); @@ -118,7 +121,7 @@ void SP::Ph1::Load::initializeFromNodesAndTerminals(Real frequency) { } if (**mReactivePower != 0) - mReactance = std::pow(**mNomVoltage, 2) / **mReactivePower; + mReactance = std::pow(mNomVoltage, 2) / **mReactivePower; else mReactance = 0; diff --git a/dpsim-models/src/SP/SP_Ph1_NetworkInjection.cpp b/dpsim-models/src/SP/SP_Ph1_NetworkInjection.cpp index 73585f32e3..d06227a02e 100644 --- a/dpsim-models/src/SP/SP_Ph1_NetworkInjection.cpp +++ b/dpsim-models/src/SP/SP_Ph1_NetworkInjection.cpp @@ -91,6 +91,8 @@ void SP::Ph1::NetworkInjection::setParameters(Complex initialPhasor, Logger::realToString(baseFrequency)); } +Real SP::Ph1::NetworkInjection::getBaseVoltage() const { return mBaseVoltage; } + void SP::Ph1::NetworkInjection::setBaseVoltage(Real baseVoltage) { mBaseVoltage = baseVoltage; } @@ -199,17 +201,17 @@ void SP::Ph1::NetworkInjection::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ + /* New state vector definintion: + * state[0]=node0_voltage + * state[1]=node1_voltage + * .... + * state[n]=noden_voltage + * state[n+1]=component0_voltage + * state[n+2]=component0_inductance (not yet implemented) + * ... + * state[m-1]=componentm_voltage + * state[m]=componentm_inductance + */ int Pos1 = matrixNodeIndex(0); int Pos2 = matrixNodeIndex(1); diff --git a/dpsim-models/src/SP/SP_Ph1_PiLine.cpp b/dpsim-models/src/SP/SP_Ph1_PiLine.cpp index acb6cad204..3c2a83898c 100644 --- a/dpsim-models/src/SP/SP_Ph1_PiLine.cpp +++ b/dpsim-models/src/SP/SP_Ph1_PiLine.cpp @@ -13,7 +13,6 @@ using namespace CPS; SP::Ph1::PiLine::PiLine(String uid, String name, Logger::Level logLevel) : Base::Ph1::PiLine(mAttributes), CompositePowerComp(uid, name, false, true, logLevel), - mBaseVoltage(mAttributes->create("base_Voltage")), mCurrent(mAttributes->create("current_vector")), mActivePowerBranch(mAttributes->create("p_branch_vector")), mReactivePowerBranch(mAttributes->create("q_branch_vector")), @@ -77,8 +76,10 @@ SimPowerComp::Ptr SP::Ph1::PiLine::clone(String name) { } // #### Powerflow section #### +Real SP::Ph1::PiLine::getBaseVoltage() const { return mBaseVoltage; } + void SP::Ph1::PiLine::setBaseVoltage(Real baseVoltage) { - **mBaseVoltage = baseVoltage; + mBaseVoltage = baseVoltage; } void SP::Ph1::PiLine::calculatePerUnitParameters(Real baseApparentPower, @@ -90,15 +91,15 @@ void SP::Ph1::PiLine::calculatePerUnitParameters(Real baseApparentPower, SPDLOG_LOGGER_INFO(mSLog, "Base Power={} [VA] Base Omega={} [1/s]", baseApparentPower, baseOmega); - mBaseImpedance = (**mBaseVoltage * **mBaseVoltage) / mBaseApparentPower; + mBaseImpedance = (mBaseVoltage * mBaseVoltage) / mBaseApparentPower; mBaseAdmittance = 1.0 / mBaseImpedance; mBaseInductance = mBaseImpedance / mBaseOmega; mBaseCapacitance = 1.0 / mBaseOmega / mBaseImpedance; mBaseCurrent = baseApparentPower / - (**mBaseVoltage * + (mBaseVoltage * sqrt(3)); // I_base=(S_threephase/3)/(V_line_to_line/sqrt(3)) SPDLOG_LOGGER_INFO(mSLog, "Base Voltage={} [V] Base Impedance={} [Ohm]", - **mBaseVoltage, mBaseImpedance); + mBaseVoltage, mBaseImpedance); mSeriesResPerUnit = **mSeriesRes / mBaseImpedance; mSeriesIndPerUnit = **mSeriesInd / mBaseInductance; diff --git a/dpsim-models/src/SP/SP_Ph1_RXLine.cpp b/dpsim-models/src/SP/SP_Ph1_RXLine.cpp index 78c1340030..f22722b06b 100644 --- a/dpsim-models/src/SP/SP_Ph1_RXLine.cpp +++ b/dpsim-models/src/SP/SP_Ph1_RXLine.cpp @@ -15,7 +15,6 @@ SP::Ph1::RXLine::RXLine(String uid, String name, Real baseVoltage, Logger::Level logLevel) : Base::Ph1::PiLine(mAttributes), CompositePowerComp(uid, name, true, true, logLevel), - mBaseVoltage(mAttributes->create("base_Voltage", baseVoltage)), mInductance(mAttributes->create("L_series")), mActivePowerInjection(mAttributes->create("p_inj")), mReactivePowerInjection(mAttributes->create("q_inj")), @@ -31,15 +30,11 @@ SP::Ph1::RXLine::RXLine(String uid, String name, Real baseVoltage, **mCurrent = MatrixComp::Zero(2, 1); **mActivePowerBranch = Matrix::Zero(2, 1); **mReactivePowerBranch = Matrix::Zero(2, 1); - // mLog.Log(Logger::Level::DEBUG) << "Create " << this->type() << " " << name - // << " R=" << resistance << " L=" << inductance - // << std::endl; } SP::Ph1::RXLine::RXLine(String uid, String name, Logger::Level logLevel) : Base::Ph1::PiLine(mAttributes), CompositePowerComp(uid, name, true, true, logLevel), - mBaseVoltage(mAttributes->create("base_Voltage")), mInductance(mAttributes->create("L_series")), mActivePowerInjection(mAttributes->create("p_inj")), mReactivePowerInjection(mAttributes->create("q_inj")), @@ -56,41 +51,22 @@ SP::Ph1::RXLine::RXLine(String uid, String name, Logger::Level logLevel) void SP::Ph1::RXLine::setPerUnitSystem(Real baseApparentPower, Real baseOmega) { mBaseApparentPower = baseApparentPower; mBaseOmega = baseOmega; - mBaseImpedance = (**mBaseVoltage * **mBaseVoltage) / mBaseApparentPower; + mBaseImpedance = (mBaseVoltage * mBaseVoltage) / mBaseApparentPower; mBaseAdmittance = 1.0 / mBaseImpedance; mBaseInductance = mBaseImpedance / mBaseOmega; - /// I_base = S_base / V_line - mBaseCurrent = baseApparentPower / (**mBaseVoltage * sqrt(3)); - /* - mLog.Log(Logger::Level::INFO) << "#### Set Per Unit System for " << **mName << std::endl; - mLog.Log(Logger::Level::INFO) << " Base Voltage= " << mBaseVoltage << " [V] " << " Base Impedance= " << mBaseImpedance << " [Ohm] " << std::endl; - */ + mBaseCurrent = baseApparentPower / (mBaseVoltage * sqrt(3)); mSeriesResPerUnit = **mSeriesRes / mBaseImpedance; mSeriesIndPerUnit = **mInductance / mBaseInductance; - /* - mLog.Log(Logger::Level::INFO) << "Series Resistance Per Unit= " << " " << mSeriesResPerUnit << " [Ohm] " - << " Series Inductance Per Unit= " << " " << mSeriesIndPerUnit << " [H] " - << std::endl; - mLog.Log(Logger::Level::INFO) << "r " << mSeriesResPerUnit << std::endl << " x: " << mBaseOmega * mInductance / mBaseImpedance<matrixNodeIndex(0); int bus2 = this->matrixNodeIndex(1); - //dimension check - /* TODO: FIX - if (bus1 > (n - 1) || bus2 > (n - 1)) { - std::stringstream ss; - ss << "Line>>" << this->getName() << ": Wrong Y dimension: " << n; - throw std::invalid_argument(ss.str()); - //std::cout << "Line>>" << Name << ": Wrong Y dimension: " << n << endl; - return; - } - */ - //create the element admittance matrix Complex y = Complex(1, 0) / Complex(mSeriesResPerUnit, 1. * mSeriesIndPerUnit); @@ -122,9 +98,6 @@ void SP::Ph1::RXLine::pfApplyAdmittanceMatrixStamp(SparseMatrixCompRow &Y) { Y.coeffRef(bus1, bus2) += mY_element.coeff(0, 1); Y.coeffRef(bus2, bus1) += mY_element.coeff(1, 0); Y.coeffRef(bus2, bus2) += mY_element.coeff(1, 1); - - //mLog.Log(Logger::Level::INFO) << "#### Y matrix stamping: " << std::endl; - //mLog.Log(Logger::Level::INFO) << mY_element << std::endl; } void SP::Ph1::RXLine::updateBranchFlow(VectorComp ¤t, diff --git a/dpsim-models/src/SP/SP_Ph1_Switch.cpp b/dpsim-models/src/SP/SP_Ph1_Switch.cpp index d10ffc2bb1..b92f0bed70 100644 --- a/dpsim-models/src/SP/SP_Ph1_Switch.cpp +++ b/dpsim-models/src/SP/SP_Ph1_Switch.cpp @@ -107,3 +107,13 @@ void SP::Ph1::Switch::mnaCompPostStep(Real time, Int timeStepCount, mnaCompUpdateVoltage(**leftVector); mnaCompUpdateCurrent(**leftVector); } + +Bool SP::Ph1::Switch::hasParameterChanged() { + // Check if state of switch changed + if (!(mIsClosedPrev == mnaIsClosed())) { + mIsClosedPrev = mnaIsClosed(); + return 1; //recompute system matrix + } else { + return 0; // do not recompute system matrix + } +}; diff --git a/dpsim-models/src/SP/SP_Ph1_SynchronGenerator.cpp b/dpsim-models/src/SP/SP_Ph1_SynchronGenerator.cpp index c5c5684fff..933d48cc20 100644 --- a/dpsim-models/src/SP/SP_Ph1_SynchronGenerator.cpp +++ b/dpsim-models/src/SP/SP_Ph1_SynchronGenerator.cpp @@ -13,7 +13,6 @@ using namespace CPS; SP::Ph1::SynchronGenerator::SynchronGenerator(String uid, String name, Logger::Level logLevel) : SimPowerComp(uid, name, logLevel), - mBaseVoltage(mAttributes->create("base_Voltage")), mSetPointActivePower(mAttributes->create("P_set")), mSetPointReactivePower(mAttributes->create("Q_set")), mSetPointVoltage(mAttributes->create("V_set")), @@ -45,8 +44,11 @@ void SP::Ph1::SynchronGenerator::setParameters( } // #### Powerflow section #### + +Real SP::Ph1::SynchronGenerator::getBaseVoltage() const { return mBaseVoltage; } + void SP::Ph1::SynchronGenerator::setBaseVoltage(Real baseVoltage) { - **mBaseVoltage = baseVoltage; + mBaseVoltage = baseVoltage; } void SP::Ph1::SynchronGenerator::calculatePerUnitParameters( @@ -60,7 +62,7 @@ void SP::Ph1::SynchronGenerator::calculatePerUnitParameters( **mSetPointActivePowerPerUnit = **mSetPointActivePower / mBaseApparentPower; **mSetPointReactivePowerPerUnit = **mSetPointReactivePower / mBaseApparentPower; - **mSetPointVoltagePerUnit = **mSetPointVoltage / **mBaseVoltage; + **mSetPointVoltagePerUnit = **mSetPointVoltage / mBaseVoltage; SPDLOG_LOGGER_INFO(mSLog, "Active Power Set Point={} [pu] Voltage Set Point={} [pu]", **mSetPointActivePowerPerUnit, **mSetPointVoltagePerUnit); diff --git a/dpsim-models/src/SP/SP_Ph1_Transformer.cpp b/dpsim-models/src/SP/SP_Ph1_Transformer.cpp index e94606355e..bee05f78e4 100644 --- a/dpsim-models/src/SP/SP_Ph1_Transformer.cpp +++ b/dpsim-models/src/SP/SP_Ph1_Transformer.cpp @@ -49,7 +49,7 @@ void SP::Ph1::Transformer::setParameters(Real nomVoltageEnd1, SPDLOG_LOGGER_INFO( mSLog, "Nominal Voltage End 1={} [V] Nominal Voltage End 2={} [V]", - **mNominalVoltageEnd1, **mNominalVoltageEnd2); + mNominalVoltageEnd1, mNominalVoltageEnd2); SPDLOG_LOGGER_INFO( mSLog, "Resistance={} [Ohm] Inductance={} [H] (referred to primary side)", **mResistance, **mInductance); @@ -78,9 +78,9 @@ void SP::Ph1::Transformer::setParameters(Real nomVoltageEnd1, /// DEPRECATED: Delete method SimPowerComp::Ptr SP::Ph1::Transformer::clone(String name) { auto copy = Transformer::make(name, mLogLevel); - copy->setParameters(**mNominalVoltageEnd1, **mNominalVoltageEnd2, - **mRatedPower, std::abs(**mRatio), std::arg(**mRatio), - **mResistance, **mInductance); + copy->setParameters(mNominalVoltageEnd1, mNominalVoltageEnd2, **mRatedPower, + std::abs(**mRatio), std::arg(**mRatio), **mResistance, + **mInductance); return copy; } @@ -100,14 +100,14 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { std::shared_ptr> tmp = mTerminals[0]; mTerminals[0] = mTerminals[1]; mTerminals[1] = tmp; - Real tmpVolt = **mNominalVoltageEnd1; - **mNominalVoltageEnd1 = **mNominalVoltageEnd2; - **mNominalVoltageEnd2 = tmpVolt; + Real tmpVolt = mNominalVoltageEnd1; + mNominalVoltageEnd1 = mNominalVoltageEnd2; + mNominalVoltageEnd2 = tmpVolt; SPDLOG_LOGGER_INFO(mSLog, "Switching terminals to have first terminal at " "higher voltage side. Updated parameters: "); SPDLOG_LOGGER_INFO( mSLog, "Nominal Voltage End 1 = {} [V] Nominal Voltage End 2 = {} [V]", - **mNominalVoltageEnd1, **mNominalVoltageEnd2); + mNominalVoltageEnd1, mNominalVoltageEnd2); SPDLOG_LOGGER_INFO(mSLog, "Tap Ratio = {} [ ] Phase Shift = {} [deg]", mRatioAbs, mRatioPhase); } @@ -149,7 +149,7 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { Real qSnub = Q_SNUB_TRANSFORMER * **mRatedPower; // A snubber conductance is added on the higher voltage side - mSnubberResistance1 = std::pow(std::abs(**mNominalVoltageEnd1), 2) / pSnub; + mSnubberResistance1 = std::pow(std::abs(mNominalVoltageEnd1), 2) / pSnub; mSubSnubResistor1 = std::make_shared(**mName + "_snub_res1", mLogLevel); mSubSnubResistor1->setParameters(mSnubberResistance1); @@ -158,13 +158,13 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { mSLog, "Snubber Resistance 1 (connected to higher voltage side {}) = {} [Ohm]", node(0)->name(), Logger::realToString(mSnubberResistance1)); - mSubSnubResistor1->setBaseVoltage(**mNominalVoltageEnd1); + mSubSnubResistor1->setBaseVoltage(mNominalVoltageEnd1); addMNASubComponent(mSubSnubResistor1, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); // A snubber conductance is added on the lower voltage side - mSnubberResistance2 = std::pow(std::abs(**mNominalVoltageEnd2), 2) / pSnub; + mSnubberResistance2 = std::pow(std::abs(mNominalVoltageEnd2), 2) / pSnub; mSubSnubResistor2 = std::make_shared(**mName + "_snub_res2", mLogLevel); mSubSnubResistor2->setParameters(mSnubberResistance2); @@ -173,7 +173,7 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { mSLog, "Snubber Resistance 2 (connected to lower voltage side {}) = {} [Ohm]", node(1)->name(), Logger::realToString(mSnubberResistance2)); - mSubSnubResistor2->setBaseVoltage(**mNominalVoltageEnd2); + mSubSnubResistor2->setBaseVoltage(mNominalVoltageEnd2); addMNASubComponent(mSubSnubResistor2, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); @@ -189,7 +189,7 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { // A snubber capacitance is added to lower voltage side mSnubberCapacitance2 = - qSnub / std::pow(std::abs(**mNominalVoltageEnd2), 2) / mNominalOmega; + qSnub / std::pow(std::abs(mNominalVoltageEnd2), 2) / mNominalOmega; mSubSnubCapacitor2 = std::make_shared(**mName + "_snub_cap2", mLogLevel); mSubSnubCapacitor2->setParameters(mSnubberCapacitance2); @@ -198,7 +198,7 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { mSLog, "Snubber Capacitance 2 (connected to lower voltage side {}) = {} [F]", node(1)->name(), Logger::realToString(mSnubberCapacitance2)); - mSubSnubCapacitor2->setBaseVoltage(**mNominalVoltageEnd2); + mSubSnubCapacitor2->setBaseVoltage(mNominalVoltageEnd2); addMNASubComponent(mSubSnubCapacitor2, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true); @@ -230,6 +230,14 @@ void SP::Ph1::Transformer::initializeFromNodesAndTerminals(Real frequency) { // #### Powerflow section #### +Real SP::Ph1::Transformer::getNominalVoltageEnd1() const { + return mNominalVoltageEnd1; +} + +Real SP::Ph1::Transformer::getNominalVoltageEnd2() const { + return mNominalVoltageEnd2; +} + void SP::Ph1::Transformer::setBaseVoltage(Real baseVoltage) { // Note: to be consistent set base voltage to higher voltage (and impedance values must be referred to high voltage side) // TODO: use attribute setter for setting base voltage @@ -264,7 +272,7 @@ void SP::Ph1::Transformer::calculatePerUnitParameters(Real baseApparentPower, mLeakagePerUnit = Complex(mResistancePerUnit, 1. * mInductancePerUnit); SPDLOG_LOGGER_INFO(mSLog, "Leakage Impedance={} [pu] ", mLeakagePerUnit); - mRatioAbsPerUnit = mRatioAbs / **mNominalVoltageEnd1 * **mNominalVoltageEnd2; + mRatioAbsPerUnit = mRatioAbs / mNominalVoltageEnd1 * mNominalVoltageEnd2; SPDLOG_LOGGER_INFO(mSLog, "Tap Ratio={} [pu]", mRatioAbsPerUnit); // Calculate per unit parameters of subcomps diff --git a/dpsim-models/src/SP/SP_Ph1_VoltageSource.cpp b/dpsim-models/src/SP/SP_Ph1_VoltageSource.cpp index 44d34e5a69..54920c08e2 100644 --- a/dpsim-models/src/SP/SP_Ph1_VoltageSource.cpp +++ b/dpsim-models/src/SP/SP_Ph1_VoltageSource.cpp @@ -206,30 +206,7 @@ void SP::Ph1::VoltageSource::mnaCompUpdateCurrent(const Matrix &leftVector) { void SP::Ph1::VoltageSource::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], - std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ - - //int Pos1 = matrixNodeIndex(0); - //int Pos2 = matrixNodeIndex(1); - //int c_offset = off[0] + off[1]; //current offset for component - //int n_offset_1 = c_offset + Pos1 + 1;// current offset for first nodal equation - //int n_offset_2 = c_offset + Pos2 + 1;// current offset for second nodal equation - //resid[c_offset] = (state[Pos2] - state[Pos1]) - state[c_offset]; // Voltage equation for Resistor - ////resid[++c_offset] = ; //TODO : add inductance equation - //resid[n_offset_1] += std::real(current()); - //resid[n_offset_2] += std::real(current()); - //off[1] += 1; -} + std::vector &off) {} Complex SP::Ph1::VoltageSource::daeInitialize() { (**mIntfVoltage)(0, 0) = mSrcSig->getSignal(); diff --git a/dpsim-models/src/SP/SP_Ph1_varResSwitch.cpp b/dpsim-models/src/SP/SP_Ph1_varResSwitch.cpp index 23daa31cef..877ba6b73d 100644 --- a/dpsim-models/src/SP/SP_Ph1_varResSwitch.cpp +++ b/dpsim-models/src/SP/SP_Ph1_varResSwitch.cpp @@ -103,11 +103,8 @@ void SP::Ph1::varResSwitch::mnaCompUpdateCurrent(const Matrix &leftVector) { } Bool SP::Ph1::varResSwitch::hasParameterChanged() { - //Get present state - Bool presentState = this->mnaIsClosed(); - // Check if state of switch changed from open to closed - if (!(mPrevState == presentState)) { + if (!(mIsClosedPrev == this->mnaIsClosed())) { // Switch is closed : change with 1/mDeltaRes if (this->mnaIsClosed() == true) { // mClosedResistance= 1./mDeltaRes*mPrevRes; @@ -117,7 +114,7 @@ Bool SP::Ph1::varResSwitch::hasParameterChanged() { if (**mClosedResistance < mInitClosedRes) { **mClosedResistance = mInitClosedRes; mPrevRes = **mClosedResistance; - mPrevState = this->mnaIsClosed(); + mIsClosedPrev = this->mnaIsClosed(); } } // Switch is opened : change with mDeltaRes @@ -128,7 +125,7 @@ Bool SP::Ph1::varResSwitch::hasParameterChanged() { if (**mOpenResistance > mInitOpenRes) { **mOpenResistance = mInitOpenRes; mPrevRes = **mOpenResistance; - mPrevState = this->mnaIsClosed(); + mIsClosedPrev = this->mnaIsClosed(); } } return 1; //recompute system matrix @@ -142,7 +139,7 @@ void SP::Ph1::varResSwitch::setInitParameters(Real timestep) { mDeltaResClosed = 0; // mDeltaResOpen = 1.5; // assumption for 1ms step size mDeltaResOpen = 0.5 * timestep / 0.001 + 1; - mPrevState = **mIsClosed; + mIsClosedPrev = **mIsClosed; mPrevRes = (**mIsClosed) ? **mClosedResistance : **mOpenResistance; mInitClosedRes = **mClosedResistance; mInitOpenRes = **mOpenResistance; diff --git a/dpsim-models/src/SP/SP_Ph3_Capacitor.cpp b/dpsim-models/src/SP/SP_Ph3_Capacitor.cpp index ac38f68188..62ff54e7ed 100644 --- a/dpsim-models/src/SP/SP_Ph3_Capacitor.cpp +++ b/dpsim-models/src/SP/SP_Ph3_Capacitor.cpp @@ -47,31 +47,11 @@ void SP::Ph3::Capacitor::initializeFromNodesAndTerminals(Real frequency) { Complex(cos(2. / 3. * M_PI), sin(2. / 3. * M_PI)); **mIntfCurrent = mSusceptance * **mIntfVoltage; - // TODO: add updated logger - /* - mLog.info() << "\n--- Initialize from power flow ---" << std::endl - << "Impedance: " << impedance << std::endl - << "Voltage across: " << std::abs((**mIntfVoltage)(0, 0)) - << "<" << Math::phaseDeg((**mIntfVoltage)(0, 0)) << std::endl - << "Current: " << std::abs((**mIntfCurrent)(0, 0)) - << "<" << Math::phaseDeg((**mIntfCurrent)(0, 0)) << std::endl - << "Terminal 0 voltage: " << std::abs(initialSingleVoltage(0)) - << "<" << Math::phaseDeg(initialSingleVoltage(0)) << std::endl - << "Terminal 1 voltage: " << std::abs(initialSingleVoltage(1)) - << "<" << Math::phaseDeg(initialSingleVoltage(1)) << std::endl - << "--- Power flow initialization finished ---" << std::endl;*/ } void SP::Ph3::Capacitor::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { updateMatrixNodeIndices(); - // TODO add updated logger - /*mLog.info() << "\n--- MNA Initialization ---" << std::endl - << "Initial voltage " << Math::abs((**mIntfVoltage)(0, 0)) - << "<" << Math::phaseDeg((**mIntfVoltage)(0, 0)) << std::endl - << "Initial current " << Math::abs((**mIntfCurrent)(0, 0)) - << "<" << Math::phaseDeg((**mIntfCurrent)(0, 0)) << std::endl - << "--- MNA initialization finished ---" << std::endl;*/ } void SP::Ph3::Capacitor::mnaCompApplySystemMatrixStamp( diff --git a/dpsim-models/src/SP/SP_Ph3_Inductor.cpp b/dpsim-models/src/SP/SP_Ph3_Inductor.cpp index e40f7007f3..b2c498826f 100644 --- a/dpsim-models/src/SP/SP_Ph3_Inductor.cpp +++ b/dpsim-models/src/SP/SP_Ph3_Inductor.cpp @@ -49,31 +49,11 @@ void SP::Ph3::Inductor::initializeFromNodesAndTerminals(Real frequency) { **mIntfCurrent = mSusceptance * **mIntfVoltage; SPDLOG_LOGGER_INFO(mSLog, "--- Initialize according to power flow ---"); - /* - mLog.info() << "--- Initialize according to power flow ---" << std::endl - << "in phase A: " << std::endl - << "Voltage across: " << std::abs((**mIntfVoltage)(0, 0)) - << "<" << Math::phaseDeg((**mIntfVoltage)(0, 0)) << std::endl - << "Current: " << std::abs((**mIntfCurrent)(0, 0)) - << "<" << Math::phaseDeg((**mIntfCurrent)(0, 0)) << std::endl - << "Terminal 0 voltage: " << std::abs(initialSingleVoltage(0)) - << "<" << Math::phaseDeg(initialSingleVoltage(0)) << std::endl - << "Terminal 1 voltage: " << std::abs(initialSingleVoltage(1)) - << "<" << Math::phaseDeg(initialSingleVoltage(1)) << std::endl - << "--- Power flow initialization finished ---" << std::endl; -*/ } void SP::Ph3::Inductor::mnaCompInitialize(Real omega, Real timeStep, Attribute::Ptr leftVector) { updateMatrixNodeIndices(); - // TODO - /* - mLog.info() << "Initial voltage " << Math::abs((**mIntfVoltage)(0, 0)) - << "<" << Math::phaseDeg((**mIntfVoltage)(0, 0)) << std::endl - << "Initial current " << Math::abs((**mIntfCurrent)(0, 0)) - << "<" << Math::phaseDeg((**mIntfCurrent)(0, 0)) << std::endl; -*/ } void SP::Ph3::Inductor::mnaCompApplySystemMatrixStamp( diff --git a/dpsim-models/src/SP/SP_Ph3_VoltageSource.cpp b/dpsim-models/src/SP/SP_Ph3_VoltageSource.cpp index a124fcb4a3..5a5e0a58c1 100644 --- a/dpsim-models/src/SP/SP_Ph3_VoltageSource.cpp +++ b/dpsim-models/src/SP/SP_Ph3_VoltageSource.cpp @@ -36,14 +36,6 @@ void SP::Ph3::VoltageSource::initializeFromNodesAndTerminals(Real frequency) { if (**mVoltageRef == Complex(0, 0)) **mVoltageRef = initialSingleVoltage(1) - initialSingleVoltage(0); - - /* - mLog.info() << "--- Initialize according to power flow ---" << std::endl; - mLog.info() << "Terminal 0 voltage: " << std::abs(initialSingleVoltage(0)) - << "<" << std::arg(initialSingleVoltage(0)) << std::endl; - mLog.info() << "Terminal 1 voltage: " << std::abs(initialSingleVoltage(1)) - << "<" << std::arg(initialSingleVoltage(1)) << std::endl; - mLog.info() << "Voltage across: " << std::abs(mVoltageRef->get()) << "<" << std::arg(mVoltageRef->get()) << std::endl;*/ } void SP::Ph3::VoltageSource::mnaCompInitialize( @@ -108,18 +100,6 @@ void SP::Ph3::VoltageSource::mnaCompApplySystemMatrixStamp( mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(1, 2), Complex(1, 0)); } - - /* - - mLog.info() << "--- System matrix stamp ---" << std::endl; - if (terminalNotGrounded(0)) { - mLog.info() << "Add " << Complex(-1, 0) << " to " << matrixNodeIndex(0) << "," << mVirtualNodes[0]->matrixNodeIndex() << std::endl; - mLog.info() << "Add " << Complex(-1, 0) << " to " << mVirtualNodes[0]->matrixNodeIndex() << "," << matrixNodeIndex(0) << std::endl; - } - if (terminalNotGrounded(1)) { - mLog.info() << "Add " << Complex(1, 0) << " to " << mVirtualNodes[0]->matrixNodeIndex() << "," << matrixNodeIndex(1) << std::endl; - mLog.info() << "Add " << Complex(1, 0) << " to " << matrixNodeIndex(1) << "," << mVirtualNodes[0]->matrixNodeIndex() << std::endl; - }*/ } void SP::Ph3::VoltageSource::mnaCompApplyRightSideVectorStamp( @@ -133,8 +113,6 @@ void SP::Ph3::VoltageSource::mnaCompApplyRightSideVectorStamp( Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), (**mIntfVoltage)(2, 0)); - - //mLog.debug() << "Add " << (**mIntfVoltage)(0,0) << " to source vector " << mVirtualNodes[0]->matrixNodeIndex() << std::endl; } void SP::Ph3::VoltageSource::updateVoltage(Real time) { @@ -193,30 +171,7 @@ void SP::Ph3::VoltageSource::mnaCompUpdateCurrent(const Matrix &leftVector) { void SP::Ph3::VoltageSource::daeResidual(double ttime, const double state[], const double dstate_dt[], double resid[], - std::vector &off) { - /* new state vector definintion: - state[0]=node0_voltage - state[1]=node1_voltage - .... - state[n]=noden_voltage - state[n+1]=component0_voltage - state[n+2]=component0_inductance (not yet implemented) - ... - state[m-1]=componentm_voltage - state[m]=componentm_inductance - */ - - //int Pos1 = matrixNodeIndex(0); - //int Pos2 = matrixNodeIndex(1); - //int c_offset = off[0] + off[1]; //current offset for component - //int n_offset_1 = c_offset + Pos1 + 1;// current offset for first nodal equation - //int n_offset_2 = c_offset + Pos2 + 1;// current offset for second nodal equation - //resid[c_offset] = (state[Pos2] - state[Pos1]) - state[c_offset]; // Voltage equation for Resistor - ////resid[++c_offset] = ; //TODO : add inductance equation - //resid[n_offset_1] += std::real(current()); - //resid[n_offset_2] += std::real(current()); - //off[1] += 1; -} + std::vector &off) {} Complex SP::Ph3::VoltageSource::daeInitialize() { (**mIntfVoltage)(0, 0) = **mVoltageRef; diff --git a/dpsim-models/src/Signal/DecouplingLineEMT_Ph3.cpp b/dpsim-models/src/Signal/DecouplingLineEMT_Ph3.cpp new file mode 100644 index 0000000000..662ed8b734 --- /dev/null +++ b/dpsim-models/src/Signal/DecouplingLineEMT_Ph3.cpp @@ -0,0 +1,160 @@ +/* Copyright 2017-2021 Institute for Automation of Complex Power Systems, + * EONERC, RWTH Aachen University + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *********************************************************************************/ + +#include "dpsim-models/MathUtils.h" +#include +#include + +using namespace CPS; +using namespace CPS::EMT::Ph3; +using namespace CPS::Signal; + +DecouplingLineEMT_Ph3::DecouplingLineEMT_Ph3(String name, + Logger::Level logLevel) + : SimSignalComp(name, name, logLevel), + mStates(mAttributes->create("states")), + mSrcCur1Ref(mAttributes->create("i_src1", Matrix::Zero(3, 1))), + mSrcCur2Ref(mAttributes->create("i_src2", Matrix::Zero(3, 1))) { + + mRes1 = EMT::Ph3::Resistor::make(name + "_r1", logLevel); + mRes2 = EMT::Ph3::Resistor::make(name + "_r2", logLevel); + mSrc1 = ControlledCurrentSource::make(name + "_i1", logLevel); + mSrc2 = ControlledCurrentSource::make(name + "_i2", logLevel); +} + +void DecouplingLineEMT_Ph3::setParameters(SimNode::Ptr node1, + SimNode::Ptr node2, + Matrix resistance, Matrix inductance, + Matrix capacitance) { + + mResistance = resistance; + mInductance = inductance; + mCapacitance = capacitance; + mNode1 = node1; + mNode2 = node2; + + mSurgeImpedance = (inductance * capacitance.inverse()).array().sqrt(); + mDelay = (inductance.array() * capacitance.array()).sqrt().maxCoeff(); + SPDLOG_LOGGER_INFO(mSLog, "surge impedance: {}", mSurgeImpedance); + SPDLOG_LOGGER_INFO(mSLog, "delay: {}", mDelay); + + mRes1->setParameters(Math::singlePhaseParameterToThreePhase( + mSurgeImpedance(0, 0) + mResistance(0, 0) / 4)); + mRes1->connect({SimNode::GND, node1}); + mRes2->setParameters(Math::singlePhaseParameterToThreePhase( + mSurgeImpedance(0, 0) + mResistance(0, 0) / 4)); + /*Notice that, as opposed to the DecouplingLine Ph1, this resistor is connected from GND to node2, + since currently the Ph3 resistor has the opposite sign convention for voltage and current, compared to the Ph1 countepart.*/ + mRes2->connect({SimNode::GND, node2}); + mSrc1->setParameters(Matrix::Zero(3, 1)); + mSrc1->connect({node1, SimNode::GND}); + mSrc2->setParameters(Matrix::Zero(3, 1)); + mSrc2->connect({node2, SimNode::GND}); + + mSrcCur1 = mSrc1->mCurrentRef; + mSrcCur2 = mSrc2->mCurrentRef; +} + +void DecouplingLineEMT_Ph3::initialize(Real omega, Real timeStep) { + if (mDelay < timeStep) + throw SystemError("Timestep too large for decoupling"); + + mBufSize = static_cast(ceil(mDelay / timeStep)); + mAlpha = 1 - (mBufSize - mDelay / timeStep); + SPDLOG_LOGGER_INFO(mSLog, "bufsize {} alpha {}", mBufSize, mAlpha); + + // Initialization based on static PI-line model + MatrixComp volt1 = -mNode1->initialVoltage(); + MatrixComp volt2 = -mNode2->initialVoltage(); + + MatrixComp initAdmittance = + (mResistance + Complex(0, omega) * mInductance).inverse() + + Complex(0, omega) * mCapacitance / 2; + MatrixComp cur1 = + initAdmittance * volt1 - + (mResistance + Complex(0, omega) * mInductance).inverse() * volt2; + MatrixComp cur2 = + initAdmittance * volt2 - + (mResistance + Complex(0, omega) * mInductance).inverse() * volt1; + + SPDLOG_LOGGER_INFO(mSLog, "initial voltages: v_k {} v_m {}", volt1, volt2); + SPDLOG_LOGGER_INFO(mSLog, "initial currents: i_km {} i_mk {}", cur1, cur2); + + // Resize ring buffers and initialize + mVolt1 = volt1.real().transpose().replicate(mBufSize, 1); + mVolt2 = volt2.real().transpose().replicate(mBufSize, 1); + mCur1 = cur1.real().transpose().replicate(mBufSize, 1); + mCur2 = cur2.real().transpose().replicate(mBufSize, 1); +} + +Matrix DecouplingLineEMT_Ph3::interpolate(Matrix &data) { + // linear interpolation of the nearest values + Matrix c1 = data.row(mBufIdx); + Matrix c2 = mBufIdx == mBufSize - 1 ? data.row(0) : data.row(mBufIdx + 1); + return (mAlpha * c1 + (1 - mAlpha) * c2).transpose(); +} + +void DecouplingLineEMT_Ph3::step(Real time, Int timeStepCount) { + Matrix volt1 = interpolate(mVolt1); + Matrix volt2 = interpolate(mVolt2); + Matrix cur1 = interpolate(mCur1); + Matrix cur2 = interpolate(mCur2); + Matrix denom = (mSurgeImpedance + (mResistance / 4)) * + (mSurgeImpedance + (mResistance / 4)); + + if (timeStepCount == 0) { + // initialization + **mSrcCur1Ref = + cur1 - (mSurgeImpedance + mResistance / 4).inverse() * volt1; + **mSrcCur2Ref = + cur2 - (mSurgeImpedance + mResistance / 4).inverse() * volt2; + } else { + // Update currents + **mSrcCur1Ref = -mSurgeImpedance * denom.inverse() * + (volt2 + (mSurgeImpedance - mResistance / 4) * cur2) - + mResistance / 4 * denom.inverse() * + (volt1 + (mSurgeImpedance - mResistance / 4) * cur1); + **mSrcCur2Ref = -mSurgeImpedance * denom.inverse() * + (volt1 + (mSurgeImpedance - mResistance / 4) * cur1) - + mResistance / 4 * denom.inverse() * + (volt2 + (mSurgeImpedance - mResistance / 4) * cur2); + } + mSrcCur1->set(**mSrcCur1Ref); + mSrcCur2->set(**mSrcCur2Ref); +} + +void DecouplingLineEMT_Ph3::PreStep::execute(Real time, Int timeStepCount) { + mLine.step(time, timeStepCount); +} + +void DecouplingLineEMT_Ph3::postStep() { + // Update ringbuffers with new values + mVolt1.row(mBufIdx) = -mRes1->intfVoltage().transpose(); + mVolt2.row(mBufIdx) = -mRes2->intfVoltage().transpose(); + mCur1.row(mBufIdx) = + -mRes1->intfCurrent().transpose() + mSrcCur1->get().real().transpose(); + mCur2.row(mBufIdx) = + -mRes2->intfCurrent().transpose() + mSrcCur2->get().real().transpose(); + + mBufIdx++; + if (mBufIdx == mBufSize) + mBufIdx = 0; +} + +void DecouplingLineEMT_Ph3::PostStep::execute(Real time, Int timeStepCount) { + mLine.postStep(); +} + +Task::List DecouplingLineEMT_Ph3::getTasks() { + return Task::List( + {std::make_shared(*this), std::make_shared(*this)}); +} + +IdentifiedObject::List DecouplingLineEMT_Ph3::getLineComponents() { + return IdentifiedObject::List({mRes1, mRes2, mSrc1, mSrc2}); +} diff --git a/dpsim-models/src/Signal/Exciter.cpp b/dpsim-models/src/Signal/Exciter.cpp index 904d2d446a..27c462d927 100644 --- a/dpsim-models/src/Signal/Exciter.cpp +++ b/dpsim-models/src/Signal/Exciter.cpp @@ -57,7 +57,6 @@ void Signal::Exciter::initialize(Real Vh_init, Real Ef_init) { **mEf = Ef_init; // mVse is the ceiling function in PSAT - // mVse = mEf * (0.33 * (exp(0.1 * abs(mEf)) - 1.)); **mVse = **mEf * (0.33 * exp(0.1 * abs(**mEf))); // mVis = vr2 in PSAT @@ -98,7 +97,6 @@ Real Signal::Exciter::step(Real mVd, Real mVq, Real dt) { **mVm = Math::StateSpaceEuler(mVm_prev, -1 / mTr, 1 / mTr, dt, **mVh); // Stabilizing feedback equation - // mVse = mEf * (0.33 * (exp(0.1 * abs(mEf)) - 1.)); **mVse = mEf_prev * (0.33 * exp(0.1 * abs(mEf_prev))); **mVis = Math::StateSpaceEuler(mVis_prev, -1 / mTf, -mKf / mTf / mTf, dt, mEf_prev); @@ -118,20 +116,3 @@ Real Signal::Exciter::step(Real mVd, Real mVq, Real dt) { return **mEf; } - -/* -// Saturation function according to Viviane thesis -Real Signal::Exciter::saturation_fcn1(Real mVd, Real mVq, Real Vref, Real dt) { - if (mEf <= 2.3) - mVse = (0.1 / 2.3)*mEf; - else - mVse = (0.33 / 3.1)*mEf; - mVse = mVse*mEf; -} - -// Saturation function according to PSAT -Real Signal::Exciter::saturation_fcn2() { - return mA * (exp(mB * abs(mEf)) - 1); -} - -*/ diff --git a/dpsim-models/src/SimPowerComp.cpp b/dpsim-models/src/SimPowerComp.cpp index 0456e7e9f9..ffdb7a93e6 100644 --- a/dpsim-models/src/SimPowerComp.cpp +++ b/dpsim-models/src/SimPowerComp.cpp @@ -271,7 +271,8 @@ void SimPowerComp::connect(typename SimNode::List nodes) { } for (UInt i = 0; i < nodes.size(); i++) { if (nodes[i] == nullptr) { - throw SystemError(fmt::format("Node is nullptr for Component {}", **mName)); + throw SystemError( + fmt::format("Node is nullptr for Component {}", **mName)); } String name = **mName + "_T" + std::to_string(i); typename SimTerminal::Ptr terminal = diff --git a/dpsim-models/src/SystemTopology.cpp b/dpsim-models/src/SystemTopology.cpp index 5330f7b334..03c932b43f 100644 --- a/dpsim-models/src/SystemTopology.cpp +++ b/dpsim-models/src/SystemTopology.cpp @@ -244,9 +244,12 @@ void SystemTopology::reset() { } void SystemTopology::removeComponent(const String &name) { - for (auto it = mComponents.begin(); it != mComponents.end(); ++it) { + for (auto it = mComponents.begin(); it != mComponents.end();) { if ((*it)->name() == name) { - mComponents.erase(it); + it = mComponents.erase( + it); // safe: returns next valid iterator when erasing + } else { + ++it; } } } @@ -422,9 +425,11 @@ Graph::Graph SystemTopology::topologyGraph() { std::stringstream label, tooltip; label << "" << name << "
"; - label << "" << type << "
"; + label << "" << type + << "
"; if (topoComp->description() != "") { - label << "" << topoComp->description() << ""; + label << "" + << topoComp->description() << ""; } tooltip << "Attributes:"; diff --git a/dpsim-villas/CMakeLists.txt b/dpsim-villas/CMakeLists.txt index 5ea6cd3950..08a8a0181b 100644 --- a/dpsim-villas/CMakeLists.txt +++ b/dpsim-villas/CMakeLists.txt @@ -1,3 +1,13 @@ +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/include/dpsim-villas/Config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/dpsim-villas/Config.h +) + +set(DPSIM_VILLAS_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include +) + if(WITH_PYBIND) pybind11_add_module(dpsimpyvillas src/pybind-dpsim-villas.cpp) set_target_properties(dpsimpyvillas @@ -5,10 +15,44 @@ if(WITH_PYBIND) LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) target_link_libraries(dpsimpyvillas PRIVATE dpsim-villas) + + install(TARGETS dpsimpyvillas + EXPORT dpsimpyvillas + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_PYTHON_SITEPACKAGESDIR} + ) endif() add_subdirectory(src) +target_include_directories(dpsim-villas PUBLIC + ${DPSIM_VILLAS_INCLUDE_DIRS} +) + if(DPSIM_BUILD_EXAMPLES) add_subdirectory(examples) endif() + +file(GLOB_RECURSE HEADER_FILES include/*.h) +set(GENERATED_HEADER ${CMAKE_CURRENT_BINARY_DIR}/include/dpsim-villas/Config.h) + +target_sources(dpsim-villas PUBLIC + FILE_SET public_headers + TYPE HEADERS + BASE_DIRS + ${DPSIM_VILLAS_INCLUDE_DIRS} + FILES + ${HEADER_FILES} + ${GENERATED_HEADER} +) + +install(TARGETS dpsim-villas + EXPORT dpsim-villas + FILE_SET public_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/dpsim-villas/examples/cxx/CMakeLists.txt b/dpsim-villas/examples/cxx/CMakeLists.txt index 51c7ceed15..e2cea68356 100644 --- a/dpsim-villas/examples/cxx/CMakeLists.txt +++ b/dpsim-villas/examples/cxx/CMakeLists.txt @@ -1,42 +1,83 @@ set(LIBRARIES "dpsim-villas") if(NOT WIN32) - # Needed so CIMParser and arabica (which are first compiled into static libs) + # Needed so CIMParser and Arabica (which are first compiled into static libs) # can be included in the .so set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() -list(APPEND LIBRARIES ${VILLASNODE_LIBRARIES}) -list(APPEND LIBRARIES "jansson") -list(APPEND LIBRARIES "uuid") -list(APPEND LIBRARIES "villas-common") -list(APPEND LIBRARIES "villas-fpga") -list(APPEND LIBRARIES "xil") +if(NOT VILLASNODE_LIBRARIES) + message(FATAL_ERROR "villas-node is required when building DPsim VILLAS examples.") +endif() + +if(NOT VILLASCOMMON_LIBRARIES) + message(FATAL_ERROR "villas-common is required when building DPsim VILLAS examples.") +endif() + +list(APPEND LIBRARIES + ${VILLASNODE_LIBRARIES} + ${VILLASCOMMON_LIBRARIES} + "jansson" + "uuid" +) + +if(VILLASFPGA_LIBRARIES) + list(APPEND LIBRARIES ${VILLASFPGA_LIBRARIES}) + list(APPEND LIBRARIES "xil") +endif() list(APPEND INCLUDE_DIRS ${VILLASNODE_INCLUDE_DIRS}) -set(SHMEM_SOURCES + +set(DPSIM_VILLAS_EXAMPLE_SOURCES FileExample.cpp MqttExample.cpp - FpgaExample.cpp - FpgaCosim3PhInfiniteBus.cpp - FpgaCosimulation.cpp - Fpga9BusHil.cpp SharedMemExample.cpp - #ShmemExample.cpp - #ShmemDistributedReference.cpp - #ShmemDistributedDirect.cpp - #ShmemDistributedVillas.cpp - #ShmemControllableSource.cpp - #ShmemControllableFiltSource.cpp - #Shmem_CIGRE_MV_PowerFlowTest.cpp - #Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp ) +set(DPSIM_VILLAS_DEPRECATED_BASE + deprecated/ShmemExample.cpp + deprecated/ShmemDistributedReference.cpp + deprecated/ShmemDistributedDirect.cpp + deprecated/ShmemDistributedVillas.cpp + deprecated/ShmemControllableSource.cpp + deprecated/ShmemControllableFiltSource.cpp +) + +set(DPSIM_VILLAS_DEPRECATED_CIM + deprecated/Shmem_CIGRE_MV_PowerFlowTest.cpp + deprecated/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp + deprecated/Shmem_WSCC-9bus.cpp + deprecated/Shmem_WSCC-9bus_Ctrl.cpp + deprecated/Shmem_WSCC-9bus_CtrlDist.cpp +) + +list(APPEND DPSIM_VILLAS_EXAMPLE_SOURCES ${DPSIM_VILLAS_DEPRECATED_BASE}) + +if(WITH_CIM) + list(APPEND DPSIM_VILLAS_EXAMPLE_SOURCES ${DPSIM_VILLAS_DEPRECATED_CIM}) +else() + message(STATUS "Skipping deprecated CIM-based shmem examples because WITH_CIM is disabled") +endif() + +if(VILLASFPGA_LIBRARIES) + list(APPEND DPSIM_VILLAS_EXAMPLE_SOURCES + FpgaExample.cpp + FpgaCosim3PhInfiniteBus.cpp + FpgaCosimulation.cpp + ) + + if(WITH_CIM) + list(APPEND DPSIM_VILLAS_EXAMPLE_SOURCES Fpga9BusHil.cpp) + endif() +elseif(WITH_CIM) + message(STATUS "Skipping FPGA-related CIM example because villas-fpga was not found.") +endif() + if(WITH_CIM) list(APPEND INCLUDE_DIRS ${CIMPP_INCLUDE_DIRS}) endif() -foreach(SOURCE ${SHMEM_SOURCES} ${CIM_SHMEM_SOURCES}) +foreach(SOURCE ${DPSIM_VILLAS_EXAMPLE_SOURCES} ${CIM_DPSIM_VILLAS_SOURCES}) get_filename_component(TARGET ${SOURCE} NAME_WE) add_executable(${TARGET} ${SOURCE}) @@ -45,8 +86,3 @@ foreach(SOURCE ${SHMEM_SOURCES} ${CIM_SHMEM_SOURCES}) target_include_directories(${TARGET} PRIVATE ${INCLUDE_DIRS}) target_compile_options(${TARGET} PUBLIC ${DPSIM_CXX_FLAGS}) endforeach() - -#add_executable(ShmemRealtimeExample ShmemExample.cpp) -#target_link_libraries(ShmemRealtimeExample ${LIBRARIES}) -#target_include_directories(ShmemRealtimeExample PRIVATE ${INCLUDE_DIRS}) -#target_compile_definitions(ShmemRealtimeExample PUBLIC REALTIME) diff --git a/dpsim-villas/examples/cxx/FileExample.cpp b/dpsim-villas/examples/cxx/FileExample.cpp index af096c7021..58227c912e 100644 --- a/dpsim-villas/examples/cxx/FileExample.cpp +++ b/dpsim-villas/examples/cxx/FileExample.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -50,12 +50,12 @@ int main(int argc, char *argv[]) { sim.setFinalTime(10.0); std::string fileConfig = R"STRING({ - "type": "file", - "uri": "logs/output.csv", - "format": "csv", - "out": { - "flush": true - } + "type": "file", + "uri": "logs/output.csv", + "format": "csv", + "out": { + "flush": true + } })STRING"; auto intf = std::make_shared(fileConfig); diff --git a/dpsim-villas/examples/cxx/Fpga9BusHil.cpp b/dpsim-villas/examples/cxx/Fpga9BusHil.cpp index cbefd327a8..93a1229b41 100644 --- a/dpsim-villas/examples/cxx/Fpga9BusHil.cpp +++ b/dpsim-villas/examples/cxx/Fpga9BusHil.cpp @@ -7,31 +7,24 @@ #include #include -#include "../examples/cxx/Examples.h" #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include + +#include "../examples/cxx/Examples.h" using namespace DPsim; using namespace CPS::EMT; using namespace CPS::EMT::Ph1; const CPS::CIM::Examples::Components::GovernorKundur::Parameters govKundur; -const CPS::CIM::Examples::Components::ExcitationSystemEremia::Parameters excEremia; +const CPS::CIM::Examples::Components::ExcitationSystemEremia::Parameters + excEremia; const std::string buildFpgaConfig(CommandLineArgs &args) { - std::filesystem::path fpgaIpPath = "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie/" - "vc707-xbar-pcie.json"; + std::filesystem::path fpgaIpPath = + "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie/" + "vc707-xbar-pcie.json"; if (args.options.find("ips") != args.options.end()) { fpgaIpPath = std::filesystem::path(args.getOptionString("ips")); @@ -83,22 +76,29 @@ const std::string buildFpgaConfig(CommandLineArgs &args) { {} }})STRING", cardConfig, signalOutConfig, signalInConfig); - DPsim::Logger::get("FpgaExample")->debug("Config for Node:\n{}", config); + SPDLOG_LOGGER_DEBUG(DPsim::Logger::get("FpgaExample"), "Config for Node:\n{}", + config); return config; } -std::pair>> hilTopology(CommandLineArgs &args, std::shared_ptr intf, std::shared_ptr logger) { +std::pair>> +hilTopology(CommandLineArgs &args, std::shared_ptr intf, + std::shared_ptr logger) { std::string simName = "Fpga9BusHil"; auto events = std::make_shared>(); - std::list filenames = - Utils::findFiles({"WSCC-09_Dyn_Full_DI.xml", "WSCC-09_Dyn_Full_EQ.xml", "WSCC-09_Dyn_Full_SV.xml", "WSCC-09_Dyn_Full_TP.xml"}, "build/_deps/cim-data-src/WSCC-09/WSCC-09_Dyn_Full", "CIMPATH"); + std::list filenames = Utils::findFiles( + {"WSCC-09_Dyn_Full_DI.xml", "WSCC-09_Dyn_Full_EQ.xml", + "WSCC-09_Dyn_Full_SV.xml", "WSCC-09_Dyn_Full_TP.xml"}, + "build/_deps/cim-data-src/WSCC-09/WSCC-09_Dyn_Full", "CIMPATH"); // ----- POWERFLOW FOR INITIALIZATION ----- // read original network topology String simNamePF = simName + "_PF"; CPS::CIM::Reader reader(simNamePF); - SystemTopology systemPF = reader.loadCIM(60, filenames, Domain::SP, PhaseType::Single, CPS::GeneratorType::PVNode); - systemPF.component("GEN1")->modifyPowerFlowBusType(CPS::PowerflowBusType::VD); + SystemTopology systemPF = reader.loadCIM( + 60, filenames, Domain::SP, PhaseType::Single, CPS::GeneratorType::PVNode); + systemPF.component("GEN1") + ->modifyPowerFlowBusType(CPS::PowerflowBusType::VD); // define logging auto loggerPF = DPsim::DataLogger::make(simNamePF); @@ -120,25 +120,42 @@ std::pair>> hilTopology( // ----- DYNAMIC SIMULATION ----- CPS::CIM::Reader reader2(simName); - SystemTopology sys = reader2.loadCIM(60, filenames, Domain::EMT, PhaseType::ABC, CPS::GeneratorType::FullOrderVBR); + SystemTopology sys = + reader2.loadCIM(60, filenames, Domain::EMT, PhaseType::ABC, + CPS::GeneratorType::FullOrderVBR); sys.initWithPowerflow(systemPF, CPS::Domain::EMT); - sys.component("LOAD5")->setParameters(Matrix({{125e6, 0, 0}, {0, 125e6, 0}, {0, 0, 125e6}}), Matrix({{90e6, 0, 0}, {0, 90e6, 0}, {0, 0, 90e6}}), 230e3, true); + sys.component("LOAD5")->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(125e6), + CPS::Math::singlePhaseParameterToThreePhase(90e6), 230e3, true); - sys.component("LOAD8")->setParameters(Matrix({{100e6, 0, 0}, {0, 100e6, 0}, {0, 0, 100e6}}), Matrix({{30e6, 0, 0}, {0, 30e6, 0}, {0, 0, 30e6}}), 230e3, true); + sys.component("LOAD8")->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(100e6), + CPS::Math::singlePhaseParameterToThreePhase(30e6), 230e3, true); - sys.component("LOAD6")->setParameters(Matrix({{90e6, 0, 0}, {0, 90e6, 0}, {0, 0, 90e6}}), Matrix({{30e6, 0, 0}, {0, 30e6, 0}, {0, 0, 30e6}}), 230e3, true); + sys.component("LOAD6")->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(90e6), + CPS::Math::singlePhaseParameterToThreePhase(30e6), 230e3, true); auto gen1 = sys.component("GEN1"); - gen1->addGovernor(govKundur.Ta_t, govKundur.Tb, govKundur.Tc, govKundur.Fa, govKundur.Fb, govKundur.Fc, govKundur.Kg, govKundur.Tsr, govKundur.Tsm, 1, 1); - gen1->addExciter(excEremia.Ta, excEremia.Ka, excEremia.Te, excEremia.Ke, excEremia.Tf, excEremia.Kf, excEremia.Tr); + gen1->addGovernor(govKundur.Ta_t, govKundur.Tb, govKundur.Tc, govKundur.Fa, + govKundur.Fb, govKundur.Fc, govKundur.Kg, govKundur.Tsr, + govKundur.Tsm, 1, 1); + gen1->addExciter(excEremia.Ta, excEremia.Ka, excEremia.Te, excEremia.Ke, + excEremia.Tf, excEremia.Kf, excEremia.Tr); auto gen2 = sys.component("GEN2"); - gen2->addGovernor(govKundur.Ta_t, govKundur.Tb, govKundur.Tc, govKundur.Fa, govKundur.Fb, govKundur.Fc, govKundur.Kg, govKundur.Tsr, govKundur.Tsm, 1, 1); - gen2->addExciter(excEremia.Ta, excEremia.Ka, excEremia.Te, excEremia.Ke, excEremia.Tf, excEremia.Kf, excEremia.Tr); + gen2->addGovernor(govKundur.Ta_t, govKundur.Tb, govKundur.Tc, govKundur.Fa, + govKundur.Fb, govKundur.Fc, govKundur.Kg, govKundur.Tsr, + govKundur.Tsm, 1, 1); + gen2->addExciter(excEremia.Ta, excEremia.Ka, excEremia.Te, excEremia.Ke, + excEremia.Tf, excEremia.Kf, excEremia.Tr); auto gen3 = sys.component("GEN3"); - gen3->addGovernor(govKundur.Ta_t, govKundur.Tb, govKundur.Tc, govKundur.Fa, govKundur.Fb, govKundur.Fc, govKundur.Kg, govKundur.Tsr, govKundur.Tsm, 1, 1); - gen3->addExciter(excEremia.Ta, excEremia.Ka, excEremia.Te, excEremia.Ke, excEremia.Tf, excEremia.Kf, excEremia.Tr); + gen3->addGovernor(govKundur.Ta_t, govKundur.Tb, govKundur.Tc, govKundur.Fa, + govKundur.Fb, govKundur.Fc, govKundur.Kg, govKundur.Tsr, + govKundur.Tsm, 1, 1); + gen3->addExciter(excEremia.Ta, excEremia.Ka, excEremia.Te, excEremia.Ke, + excEremia.Tf, excEremia.Kf, excEremia.Tr); auto cs = Ph1::CurrentSource::make("cs"); cs->setParameters(Complex(0, 0)); @@ -154,25 +171,37 @@ std::pair>> hilTopology( // We scale the voltage so we map the nominal voltage in the simulation (230kV) to a nominal real peak voltage // of 15V. The amplifier has a gain of 20, so the voltage before the amplifier is 1/20 of the voltage at the load. constexpr double voltage_scale = 15. * 1.414 / (230e3 * 20.); - auto updateFn = std::make_shared::Actor>([](std::shared_ptr &dependent, typename CPS::Attribute::Ptr dependency) { - *dependent = *dependency * voltage_scale; - if (*dependent > 1.) { - *dependent = 1.; - } else if (*dependent < -1.) { - *dependent = -1.; - } - }); - scaledOutputVoltage->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, - CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, sys.node("BUS6")->mVoltage->deriveCoeff(0, 0))); + auto updateFn = std::make_shared::Actor>( + [](std::shared_ptr &dependent, + typename CPS::Attribute::Ptr dependency) { + *dependent = *dependency * voltage_scale; + if (*dependent > 1.) { + *dependent = 1.; + } else if (*dependent < -1.) { + *dependent = -1.; + } + }); + scaledOutputVoltage->addTask( + CPS::UpdateTaskKind::UPDATE_ON_GET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, + sys.node("BUS6")->mVoltage->deriveCoeff(0, 0))); auto voltageInterfaceActive = CPS::AttributeStatic::make(false); - auto voltageActiveFn = std::make_shared::Actor>([](std::shared_ptr &dependent, typename CPS::Attribute::Ptr dependency) { - if (!*dependency) { - *dependent = 0.; - } - }); - scaledOutputVoltage->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_GET, *voltageActiveFn, voltageInterfaceActive)); + auto voltageActiveFn = + std::make_shared::Actor>( + [](std::shared_ptr &dependent, + typename CPS::Attribute::Ptr dependency) { + if (!*dependency) { + *dependent = 0.; + } + }); + scaledOutputVoltage->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_GET, + *voltageActiveFn, voltageInterfaceActive)); // We activate the voltage interface after 2 seconds to allow the current sensors to stabilize. - auto activeVoltageEvent = AttributeEvent::make(2., voltageInterfaceActive, true); + auto activeVoltageEvent = + AttributeEvent::make(2., voltageInterfaceActive, true); events->push_back(activeVoltageEvent); // We scale the current using a gain so that we get a load in the simulation in the MVA range. @@ -182,20 +211,33 @@ std::pair>> hilTopology( constexpr double current_offset = -2.483036; auto scaledCurrent = CPS::AttributeDynamic::make(0); auto closedLoop = CPS::AttributeStatic::make(false); - auto currentScaleFn = std::make_shared::Actor>([](std::shared_ptr &dependent, typename CPS::Attribute::Ptr dependency) { - if (!*dependency) { - *dependent = 0.; - } else { - *dependent = (*dependent + current_offset) * current_scale; - } - }); - scaledCurrent->addTask(CPS::UpdateTaskKind::UPDATE_ON_SET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_SET, *currentScaleFn, closedLoop)); + auto currentScaleFn = + std::make_shared::Actor>( + [](std::shared_ptr &dependent, + typename CPS::Attribute::Ptr dependency) { + if (!*dependency) { + *dependent = 0.; + } else { + *dependent = (*dependent + current_offset) * current_scale; + } + }); + scaledCurrent->addTask( + CPS::UpdateTaskKind::UPDATE_ON_SET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_SET, *currentScaleFn, closedLoop)); auto closeLoopEvent = AttributeEvent::make(2., closedLoop, true); events->push_back(closeLoopEvent); - auto currentCopyFn = std::make_shared::Actor>( - [](std::shared_ptr &dependent, typename CPS::Attribute::Ptr dependency) { dependency->set(Complex(*dependent, 0)); }); - scaledCurrent->addTask(CPS::UpdateTaskKind::UPDATE_ON_SET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_SET, *currentCopyFn, cs->mCurrentRef)); + auto currentCopyFn = + std::make_shared::Actor>( + [](std::shared_ptr &dependent, + typename CPS::Attribute::Ptr dependency) { + dependency->set(Complex(*dependent, 0)); + }); + scaledCurrent->addTask( + CPS::UpdateTaskKind::UPDATE_ON_SET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_SET, *currentCopyFn, cs->mCurrentRef)); intf->addImport(seqnumAttribute, true, true); intf->addImport(scaledCurrent, true, true); @@ -219,15 +261,20 @@ std::pair>> hilTopology( } int main(int argc, char *argv[]) { - CommandLineArgs args(argc, argv, "Fpga9BusHil", 0.01, 10 * 60, 60., -1, CPS::Logger::Level::info, CPS::Logger::Level::off, false, false, false, CPS::Domain::EMT); + CommandLineArgs args(argc, argv, "Fpga9BusHil", 0.01, 10 * 60, 60., -1, + CPS::Logger::Level::info, CPS::Logger::Level::off, false, + false, false, CPS::Domain::EMT); CPS::Logger::setLogDir("logs/" + args.name); - bool log = args.options.find("log") != args.options.end() && args.getOptionBool("log"); + bool log = args.options.find("log") != args.options.end() && + args.getOptionBool("log"); - auto intf = std::make_shared(buildFpgaConfig(args), "Fpga9BusHil", spdlog::level::off); + auto intf = std::make_shared( + buildFpgaConfig(args), "Fpga9BusHil", spdlog::level::off); std::filesystem::path logFilename = "logs/" + args.name + "/Fpga9BusHil.csv"; std::shared_ptr logger = nullptr; if (log) { - logger = RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); + logger = + RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); } auto topo = hilTopology(args, intf, logger); @@ -247,7 +294,7 @@ int main(int argc, char *argv[]) { sim.run(); - CPS::Logger::get("FpgaExample")->info("Simulation finished."); + SPDLOG_LOGGER_INFO(CPS::Logger::get("FpgaExample"), "Simulation finished."); sim.logStepTimes("FpgaExample"); topo.first.renderToFile("Fpga9BusHil.svg"); } diff --git a/dpsim-villas/examples/cxx/FpgaCosim3PhInfiniteBus.cpp b/dpsim-villas/examples/cxx/FpgaCosim3PhInfiniteBus.cpp index 4e03d89b72..aa0a865a02 100644 --- a/dpsim-villas/examples/cxx/FpgaCosim3PhInfiniteBus.cpp +++ b/dpsim-villas/examples/cxx/FpgaCosim3PhInfiniteBus.cpp @@ -6,31 +6,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include using namespace DPsim; using namespace CPS::EMT; const std::string buildFpgaConfig(CommandLineArgs &args) { - std::filesystem::path fpgaIpPath = "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie/" - "vc707-xbar-pcie.json"; + std::filesystem::path fpgaIpPath = + "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie/" + "vc707-xbar-pcie.json"; ; if (args.options.find("ips") != args.options.end()) { @@ -132,11 +121,14 @@ const std::string buildFpgaConfig(CommandLineArgs &args) { {} }})STRING", cardConfig, signalOutConfig, signalInConfig); - DPsim::Logger::get("FpgaCosim3PhInfiniteBus")->debug("Config for Node:\n{}", config); + SPDLOG_LOGGER_DEBUG(DPsim::Logger::get("FpgaCosim3PhInfiniteBus"), + "Config for Node:\n{}", config); return config; } -SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr intfFpga, std::shared_ptr logger) { +SystemTopology buildTopology(CommandLineArgs &args, + std::shared_ptr intfFpga, + std::shared_ptr logger) { // Nodes auto bus1 = SimNode::make("bus1", PhaseType::ABC); auto bus2 = SimNode::make("bus2", PhaseType::ABC); @@ -144,18 +136,20 @@ SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr i // Components auto vs = Ph3::VoltageSource::make("vs"); - vs->setParameters(CPS::Math::singlePhaseVariableToThreePhase(CPS::Math::polar(230e3, 0)), 50); + vs->setParameters( + CPS::Math::singlePhaseVariableToThreePhase(CPS::Math::polar(230e3, 0)), + 50); auto r = Ph3::Resistor::make("R"); - r->setParameters(Matrix{{10.4275, 0, 0}, {0, 10.4275, 0}, {0, 0, 10.4275}}); + r->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10.4275)); auto l = Ph3::Inductor::make("L"); - l->setParameters(Matrix{{0.325101, 0, 0}, {0, 0.325101, 0}, {0, 0, 0.325101}}); + l->setParameters(CPS::Math::singlePhaseParameterToThreePhase(0.325101)); auto r2 = Ph3::Resistor::make("R2"); - r2->setParameters(Matrix{{5.29e6, 0, 0}, {0, 5.29e6, 0}, {0, 0, 5.29e6}}); + r2->setParameters(CPS::Math::singlePhaseParameterToThreePhase(5.29e6)); auto cs = Ph3::ControlledCurrentSource::make("cs"); - cs->setParameters(Matrix{{0.0}, {0.0}, {0.0}}); + cs->setParameters(CPS::Math::singlePhaseParameterToThreePhase(0.0)); // Topology vs->connect({SimNode::GND, bus1}); @@ -168,10 +162,20 @@ SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr i auto seqFromRTDSAttribute = CPS::AttributeStatic::make(0); auto seqFromDPsimAttribute = CPS::AttributeStatic::make(0); auto seqToDPsimAttribute = CPS::AttributeDynamic::make(0); - auto updateFn = std::make_shared::Actor>([](std::shared_ptr &dependent, typename CPS::Attribute::Ptr dependency) { *dependent = *dependent + 1; }); - seqToDPsimAttribute->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, seqFromDPsimAttribute)); + auto updateFn = std::make_shared::Actor>( + [](std::shared_ptr &dependent, + typename CPS::Attribute::Ptr dependency) { + *dependent = *dependent + 1; + }); + seqToDPsimAttribute->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_GET, + *updateFn, seqFromDPsimAttribute)); auto seqNumForRTDS = CPS::AttributeDynamic::make(0); - seqNumForRTDS->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, seqFromDPsimAttribute)); + seqNumForRTDS->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, + seqFromDPsimAttribute)); intfFpga->addImport(seqFromRTDSAttribute, true, true); intfFpga->addImport(seqFromDPsimAttribute, true, true); @@ -196,20 +200,29 @@ SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr i logger->logAttribute("c_i", cs->mIntfCurrent->deriveCoeff(2, 0)); } - return SystemTopology(args.sysFreq, SystemNodeList{SimNode::GND, bus1, bus2, bus3}, SystemComponentList{vs, cs, r, l, r2}); + return SystemTopology(args.sysFreq, + SystemNodeList{SimNode::GND, bus1, bus2, bus3}, + SystemComponentList{vs, cs, r, l, r2}); } int main(int argc, char *argv[]) { - CommandLineArgs args(argc, argv, "FpgaCosim3PhInfiniteBus", 0.01, 10 * 60, 50., -1, CPS::Logger::Level::info, CPS::Logger::Level::off, false, false, false, CPS::Domain::EMT); + CommandLineArgs args(argc, argv, "FpgaCosim3PhInfiniteBus", 0.01, 10 * 60, + 50., -1, CPS::Logger::Level::info, + CPS::Logger::Level::off, false, false, false, + CPS::Domain::EMT); CPS::Logger::setLogDir("logs/" + args.name); - bool log = args.options.find("log") != args.options.end() && args.getOptionBool("log"); + bool log = args.options.find("log") != args.options.end() && + args.getOptionBool("log"); - auto intfFpga = std::make_shared(buildFpgaConfig(args), "FpgaInterface", spdlog::level::off); + auto intfFpga = std::make_shared( + buildFpgaConfig(args), "FpgaInterface", spdlog::level::off); - std::filesystem::path logFilename = "logs/" + args.name + "/FpgaCosim3PhInfiniteBus.csv"; + std::filesystem::path logFilename = + "logs/" + args.name + "/FpgaCosim3PhInfiniteBus.csv"; std::shared_ptr logger = nullptr; if (log) { - logger = RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); + logger = + RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); } auto sys = buildTopology(args, intfFpga, logger); @@ -224,7 +237,8 @@ int main(int argc, char *argv[]) { } sim.run(); - CPS::Logger::get("FpgaCosim3PhInfiniteBus")->info("Simulation finished."); + SPDLOG_LOGGER_INFO(CPS::Logger::get("FpgaCosim3PhInfiniteBus"), + "Simulation finished."); sim.logStepTimes("FpgaCosim3PhInfiniteBus"); // std::ofstream of("task_dependencies.svg"); diff --git a/dpsim-villas/examples/cxx/FpgaCosimulation.cpp b/dpsim-villas/examples/cxx/FpgaCosimulation.cpp index 077fab07b4..1819d3e6b6 100644 --- a/dpsim-villas/examples/cxx/FpgaCosimulation.cpp +++ b/dpsim-villas/examples/cxx/FpgaCosimulation.cpp @@ -6,27 +6,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include using namespace DPsim; using namespace CPS::EMT; const std::string buildFpgaConfig(CommandLineArgs &args) { - std::filesystem::path fpgaIpPath = "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie-dino/" - "vc707-xbar-pcie-dino-v2.json"; + std::filesystem::path fpgaIpPath = + "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie-dino/" + "vc707-xbar-pcie-dino-v2.json"; ; if (args.options.find("ips") != args.options.end()) { @@ -128,23 +122,26 @@ const std::string buildFpgaConfig(CommandLineArgs &args) { {} }})STRING", cardConfig, signalOutConfig, signalInConfig); - DPsim::Logger::get("FpgaExample")->debug("Config for Node:\n{}", config); + SPDLOG_LOGGER_DEBUG(DPsim::Logger::get("FpgaExample"), "Config for Node:\n{}", + config); return config; } -SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr intfFpga, std::shared_ptr logger) { +SystemTopology buildTopology(CommandLineArgs &args, + std::shared_ptr intfFpga, + std::shared_ptr logger) { // Nodes auto bus = SimNode::make("bus", PhaseType::ABC); // Components auto vs = Ph3::ControlledVoltageSource::make("vs"); - auto voltageRef = Matrix({{230e3}, {230e3}, {230e3}}); + auto voltageRef = CPS::Math::singlePhaseParameterToThreePhase(230e3); vs->setParameters(voltageRef); auto load = Ph3::RXLoad::make("load"); - auto active = Matrix({{125e6, 0, 0}, {0, 125e6, 0}, {0, 0, 125e6}}); + auto active = CPS::Math::singlePhaseParameterToThreePhase(125e6); // auto reactive = Matrix::Zero(3, 3); - auto reactive = Matrix({{50e6, 0, 0}, {0, 50e6, 0}, {0, 0, 50e6}}); + auto reactive = CPS::Math::singlePhaseParameterToThreePhase(50e6); load->setParameters(active, reactive, 230e3, true); // Topology @@ -155,10 +152,20 @@ SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr i auto seqFromRTDSAttribute = CPS::AttributeStatic::make(0); auto seqFromDPsimAttribute = CPS::AttributeStatic::make(0); auto seqToDPsimAttribute = CPS::AttributeDynamic::make(0); - auto updateFn = std::make_shared::Actor>([](std::shared_ptr &dependent, typename CPS::Attribute::Ptr dependency) { *dependent = *dependent + 1; }); - seqToDPsimAttribute->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, seqFromDPsimAttribute)); + auto updateFn = std::make_shared::Actor>( + [](std::shared_ptr &dependent, + typename CPS::Attribute::Ptr dependency) { + *dependent = *dependent + 1; + }); + seqToDPsimAttribute->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_GET, + *updateFn, seqFromDPsimAttribute)); auto seqNumForRTDS = CPS::AttributeDynamic::make(0); - seqNumForRTDS->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, CPS::AttributeUpdateTask::make(CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, seqFromDPsimAttribute)); + seqNumForRTDS->addTask(CPS::UpdateTaskKind::UPDATE_ON_GET, + CPS::AttributeUpdateTask::make( + CPS::UpdateTaskKind::UPDATE_ON_GET, *updateFn, + seqFromDPsimAttribute)); intfFpga->addImport(seqFromRTDSAttribute, true, true); intfFpga->addImport(seqFromDPsimAttribute, true, true); @@ -183,20 +190,27 @@ SystemTopology buildTopology(CommandLineArgs &args, std::shared_ptr i logger->logAttribute("c_i", load->mIntfCurrent->deriveCoeff(2, 0)); } - return SystemTopology(args.sysFreq, SystemNodeList{SimNode::GND, bus}, SystemComponentList{vs, load}); + return SystemTopology(args.sysFreq, SystemNodeList{SimNode::GND, bus}, + SystemComponentList{vs, load}); } int main(int argc, char *argv[]) { - CommandLineArgs args(argc, argv, "FpgaCosimulation", 0.01, 10 * 60, 60., -1, CPS::Logger::Level::info, CPS::Logger::Level::off, false, false, false, CPS::Domain::EMT); + CommandLineArgs args(argc, argv, "FpgaCosimulation", 0.01, 10 * 60, 60., -1, + CPS::Logger::Level::info, CPS::Logger::Level::off, false, + false, false, CPS::Domain::EMT); CPS::Logger::setLogDir("logs/" + args.name); - bool log = args.options.find("log") != args.options.end() && args.getOptionBool("log"); + bool log = args.options.find("log") != args.options.end() && + args.getOptionBool("log"); - auto intfFpga = std::make_shared(buildFpgaConfig(args), "FpgaInterface", spdlog::level::off); + auto intfFpga = std::make_shared( + buildFpgaConfig(args), "FpgaInterface", spdlog::level::off); - std::filesystem::path logFilename = "logs/" + args.name + "/FpgaCosimulation.csv"; + std::filesystem::path logFilename = + "logs/" + args.name + "/FpgaCosimulation.csv"; std::shared_ptr logger = nullptr; if (log) { - logger = RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); + logger = + RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); } auto sys = buildTopology(args, intfFpga, logger); @@ -211,7 +225,8 @@ int main(int argc, char *argv[]) { } sim.run(); - CPS::Logger::get("FpgaCosimulation")->info("Simulation finished."); + SPDLOG_LOGGER_INFO(CPS::Logger::get("FpgaCosimulation"), + "Simulation finished."); sim.logStepTimes("FpgaCosimulation"); // std::ofstream of("task_dependencies.svg"); diff --git a/dpsim-villas/examples/cxx/FpgaExample.cpp b/dpsim-villas/examples/cxx/FpgaExample.cpp index 24d90ba042..c8a3cfed5b 100644 --- a/dpsim-villas/examples/cxx/FpgaExample.cpp +++ b/dpsim-villas/examples/cxx/FpgaExample.cpp @@ -7,27 +7,18 @@ #include #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include using namespace DPsim; -using namespace CPS::DP; -using namespace CPS::DP::Ph1; const std::string buildFpgaConfig(CommandLineArgs &args) { - std::filesystem::path fpgaIpPath = "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie-dino/" - "vc707-xbar-pcie-dino.json"; + std::filesystem::path fpgaIpPath = + "/usr/local/etc/villas/node/etc/fpga/vc707-xbar-pcie-dino/" + "vc707-xbar-pcie-dino.json"; if (args.options.find("ips") != args.options.end()) { fpgaIpPath = std::filesystem::path(args.getOptionString("ips")); @@ -91,23 +82,26 @@ const std::string buildFpgaConfig(CommandLineArgs &args) { {} }})STRING", cardConfig, signalOutConfig, signalInConfig); - DPsim::Logger::get("FpgaExample")->debug("Config for Node:\n{}", config); + SPDLOG_LOGGER_DEBUG(DPsim::Logger::get("FpgaExample"), "Config for Node:\n{}", + config); return config; } -SystemTopology loopbackTopology(CommandLineArgs &args, std::shared_ptr intf, std::shared_ptr logger) { +SystemTopology loopbackTopology(CommandLineArgs &args, + std::shared_ptr intf, + std::shared_ptr logger) { // Nodes - auto n1 = SimNode::make("n1"); + auto n1 = CPS::DP::SimNode::make("n1"); // Components - auto vs = VoltageSource::make("v_s"); + auto vs = CPS::DP::Ph1::VoltageSource::make("v_s"); vs->setParameters(10.); - auto rl = Resistor::make("r_l"); + auto rl = CPS::DP::Ph1::Resistor::make("r_l"); rl->setParameters(1); // Topology - vs->connect({n1, SimNode::GND}); - rl->connect({n1, SimNode::GND}); + vs->connect({n1, CPS::DP::SimNode::GND}); + rl->connect({n1, CPS::DP::SimNode::GND}); // Interface auto seqnumAttribute = CPS::AttributeStatic::make(0); @@ -121,28 +115,30 @@ SystemTopology loopbackTopology(CommandLineArgs &args, std::shared_ptrlogAttribute("rl_i", rl->mIntfCurrent); } - return SystemTopology(args.sysFreq, SystemNodeList{SimNode::GND, n1}, + return SystemTopology(args.sysFreq, SystemNodeList{CPS::DP::SimNode::GND, n1}, SystemComponentList{vs, rl}); } -SystemTopology hilTopology(CommandLineArgs &args, std::shared_ptr intf, std::shared_ptr logger) { +SystemTopology hilTopology(CommandLineArgs &args, + std::shared_ptr intf, + std::shared_ptr logger) { // Nodes - auto n1 = SimNode::make("n1"); - auto n2 = SimNode::make("n2"); + auto n1 = CPS::DP::SimNode::make("n1"); + auto n2 = CPS::DP::SimNode::make("n2"); // Components - auto vs = VoltageSource::make("v_s"); + auto vs = CPS::DP::Ph1::VoltageSource::make("v_s"); vs->setParameters(Complex(1, 0), 50); - auto rs = Resistor::make("r_s"); + auto rs = CPS::DP::Ph1::Resistor::make("r_s"); rs->setParameters(1); - auto cs = CurrentSource::make("i_l"); + auto cs = CPS::DP::Ph1::CurrentSource::make("i_l"); cs->setParameters(Complex(0, 0)); // Topology - vs->connect({n1, SimNode::GND}); + vs->connect({n1, CPS::DP::SimNode::GND}); cs->connect({n1, n2}); - rs->connect({n2, SimNode::GND}); + rs->connect({n2, CPS::DP::SimNode::GND}); // Interface auto seqnumAttribute = CPS::AttributeStatic::make(0); @@ -157,26 +153,30 @@ SystemTopology hilTopology(CommandLineArgs &args, std::shared_ptr int logger->logAttribute("cs_i", cs->mIntfCurrent); } - return SystemTopology(args.sysFreq, SystemNodeList{SimNode::GND, n1, n2}, SystemComponentList{vs, rs, cs}); + return SystemTopology(args.sysFreq, + SystemNodeList{CPS::DP::SimNode::GND, n1, n2}, + SystemComponentList{vs, rs, cs}); } -SystemTopology profileTopology(CommandLineArgs &args, std::shared_ptr intf, std::shared_ptr logger) { +SystemTopology profileTopology(CommandLineArgs &args, + std::shared_ptr intf, + std::shared_ptr logger) { // Nodes - auto n1 = SimNode::make("n1"); - auto n2 = SimNode::make("n2"); + auto n1 = CPS::DP::SimNode::make("n1"); + auto n2 = CPS::DP::SimNode::make("n2"); // Components - auto vs = ProfileVoltageSource::make("v_s", "data.bin"); - auto rs = Resistor::make("r_s"); + auto vs = CPS::DP::Ph1::ProfileVoltageSource::make("v_s", "data.bin"); + auto rs = CPS::DP::Ph1::Resistor::make("r_s"); rs->setParameters(1); - auto cs = CurrentSource::make("i_l"); + auto cs = CPS::DP::Ph1::CurrentSource::make("i_l"); cs->setParameters(Complex(0, 0)); // Topology - vs->connect({n1, SimNode::GND}); + vs->connect({n1, CPS::DP::SimNode::GND}); cs->connect({n1, n2}); - rs->connect({n2, SimNode::GND}); + rs->connect({n2, CPS::DP::SimNode::GND}); // Interface auto seqnumAttribute = CPS::AttributeStatic::make(0); @@ -191,10 +191,14 @@ SystemTopology profileTopology(CommandLineArgs &args, std::shared_ptr logger->logAttribute("cs_i", cs->mIntfCurrent); } - return SystemTopology(args.sysFreq, SystemNodeList{SimNode::GND, n1, n2}, SystemComponentList{vs, rs, cs}); + return SystemTopology(args.sysFreq, + SystemNodeList{CPS::DP::SimNode::GND, n1, n2}, + SystemComponentList{vs, rs, cs}); } -SystemTopology getTopology(CommandLineArgs &args, std::shared_ptr intf, std::shared_ptr logger) { +SystemTopology getTopology(CommandLineArgs &args, + std::shared_ptr intf, + std::shared_ptr logger) { if (args.options.find("topology") != args.options.end()) { std::string topology = args.getOptionString("topology"); if (topology == "hil") { @@ -217,17 +221,22 @@ std::shared_ptr getEvent(CommandLineArgs &args, SystemTopology &sys) { std::string event = args.getOptionString("event"); if (event == "frequencyDrop") { if (topology != "hil") { - throw std::runtime_error("frequencyDrop event only supported for topology \"hil\"."); + throw std::runtime_error( + "frequencyDrop event only supported for topology \"hil\"."); } - auto vs = std::dynamic_pointer_cast(sys.mComponents[0]); - return AttributeEvent::make(3, vs->mSrcFreq, 45.); + auto vs = std::dynamic_pointer_cast( + sys.mComponents[0]); + return AttributeEvent::make(3, vs->mSrcFreq, 45.); } if (event == "voltageDrop") { if (topology != "hil") { - throw std::runtime_error("voltageDrop event only supported for topology \"hil\"."); + throw std::runtime_error( + "voltageDrop event only supported for topology \"hil\"."); } - auto vs = std::dynamic_pointer_cast(sys.mComponents[0]); - return AttributeEvent::make(3, vs->mVoltageRef->deriveReal(), 0.7); + auto vs = std::dynamic_pointer_cast( + sys.mComponents[0]); + return AttributeEvent::make(3, vs->mVoltageRef->deriveReal(), + 0.7); } } return nullptr; @@ -236,14 +245,16 @@ std::shared_ptr getEvent(CommandLineArgs &args, SystemTopology &sys) { int main(int argc, char *argv[]) { CommandLineArgs args(argc, argv, "FpgaExample", 0.01, 10 * 60, 5.); CPS::Logger::setLogDir("logs/" + args.name); - bool log = args.options.find("log") != args.options.end() && args.getOptionBool("log"); + bool log = args.options.find("log") != args.options.end() && + args.getOptionBool("log"); auto intf = std::make_shared( buildFpgaConfig(args), "FpgaExample", spdlog::level::off); std::filesystem::path logFilename = "logs/" + args.name + "/FpgaExample.csv"; std::shared_ptr logger = nullptr; if (log) { - logger = RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); + logger = + RealTimeDataLogger::make(logFilename, args.duration, args.timeStep); } auto sys = getTopology(args, intf, logger); @@ -263,7 +274,7 @@ int main(int argc, char *argv[]) { } sim.run(); - CPS::Logger::get("FpgaExample")->info("Simulation finished."); + SPDLOG_LOGGER_INFO(CPS::Logger::get("FpgaExample"), "Simulation finished."); sim.logStepTimes("FpgaExample"); //std::ofstream of("task_dependencies.svg"); diff --git a/dpsim-villas/examples/cxx/MqttExample.cpp b/dpsim-villas/examples/cxx/MqttExample.cpp index 5cb152100a..92e7801bbd 100644 --- a/dpsim-villas/examples/cxx/MqttExample.cpp +++ b/dpsim-villas/examples/cxx/MqttExample.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include using namespace DPsim; using namespace CPS::DP; diff --git a/dpsim-villas/examples/cxx/SharedMemExample.cpp b/dpsim-villas/examples/cxx/SharedMemExample.cpp index 1fe3c453ac..1d492b5d5b 100644 --- a/dpsim-villas/examples/cxx/SharedMemExample.cpp +++ b/dpsim-villas/examples/cxx/SharedMemExample.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -50,15 +50,15 @@ int main(int argc, char *argv[]) { sim.setFinalTime(2.0); std::string shmemConfig = R"STRING( - { - "type": "shmem", - "in": { - "name": "shmem-dpsim" - }, - "out": { - "name": "dpsim-shmem" - }, - "queuelen": 1024 + { + "type": "shmem", + "in": { + "name": "shmem-dpsim" + }, + "out": { + "name": "dpsim-shmem" + }, + "queuelen": 1024 })STRING"; auto intf = std::make_shared(shmemConfig); diff --git a/dpsim-villas/examples/cxx/ShmemControllableFiltSource.cpp b/dpsim-villas/examples/cxx/deprecated/ShmemControllableFiltSource.cpp similarity index 72% rename from dpsim-villas/examples/cxx/ShmemControllableFiltSource.cpp rename to dpsim-villas/examples/cxx/deprecated/ShmemControllableFiltSource.cpp index dac1cd023d..9935283c5e 100644 --- a/dpsim-villas/examples/cxx/ShmemControllableFiltSource.cpp +++ b/dpsim-villas/examples/cxx/deprecated/ShmemControllableFiltSource.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include +#include using namespace DPsim; using namespace CPS::Signal; @@ -13,7 +13,19 @@ int main(int argc, char *argv[]) { Real finalTime = 10; String simName = "ShmemControllableSource"; - InterfaceShmem intf("/dpsim01", "/dpsim10"); + const std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "dpsim01" + }, + "out": { + "name": "dpsim10" + }, + "queuelen": 1024 + })STRING"; + + auto intf = std::make_shared(shmemConfig); // Controllers and filter std::vector coefficients = { @@ -49,21 +61,34 @@ int main(int argc, char *argv[]) { load->mActivePower->setReference(filtP->mOutput); load->mReactivePower->setReference(filtQ->mOutput); - filtP->setInput(intf.importReal(0)); - filtQ->setInput(intf.importReal(1)); + auto filtPInput = CPS::AttributeDynamic::make(0.0); + intf->importAttribute(filtPInput, 0, true); + filtP->setInput(filtPInput); + + auto filtQInput = CPS::AttributeDynamic::make(0.0); + intf->importAttribute(filtQInput, 1, true); + filtQ->setInput(filtQInput); auto sys = SystemTopology(50, SystemNodeList{n1}, SystemComponentList{ecs, r1, load, filtP, filtQ}); +#ifdef WITH_RT RealTimeSimulation sim(simName, CPS::Logger::Level::info); +#else + Simulation sim(simName, CPS::Logger::Level::info); +#endif sim.setSystem(sys); sim.setTimeStep(timeStep); sim.setFinalTime(finalTime); sim.setDomain(Domain::DP); sim.setSolverType(Solver::Type::MNA); - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); +#ifdef WITH_RT + sim.run(10); +#else sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/ShmemControllableSource.cpp b/dpsim-villas/examples/cxx/deprecated/ShmemControllableSource.cpp similarity index 59% rename from dpsim-villas/examples/cxx/ShmemControllableSource.cpp rename to dpsim-villas/examples/cxx/deprecated/ShmemControllableSource.cpp index a0ed24a867..5add06c0c2 100644 --- a/dpsim-villas/examples/cxx/ShmemControllableSource.cpp +++ b/dpsim-villas/examples/cxx/deprecated/ShmemControllableSource.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -12,7 +12,19 @@ int main(int argc, char *argv[]) { Real finalTime = 10; String simName = "ShmemControllableSource"; - InterfaceShmem intf("/dpsim01", "/dpsim10"); + const std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "dpsim01" + }, + "out": { + "name": "dpsim10" + }, + "queuelen": 1024 + })STRING"; + + auto intf = std::make_shared(shmemConfig); // Nodes auto n1 = SimNode::make("n1"); @@ -26,21 +38,29 @@ int main(int argc, char *argv[]) { ecs->connect({SimNode::GND, n1}); r1->connect({SimNode::GND, n1}); - intf.importAttribute(ecs->mCurrentRef, 0); - intf.exportAttribute(ecs->mIntfVoltage->deriveCoeff(0, 0), 0); + intf->importAttribute(ecs->mCurrentRef, 0, true); + intf->exportAttribute(ecs->mIntfVoltage->deriveCoeff(0, 0), 0, true); auto sys = SystemTopology(50, SystemNodeList{n1}, SystemComponentList{ecs, r1}); +#ifdef WITH_RT RealTimeSimulation sim(simName, CPS::Logger::Level::info); +#else + Simulation sim(simName, CPS::Logger::Level::info); +#endif sim.setSystem(sys); sim.setTimeStep(timeStep); sim.setFinalTime(finalTime); sim.setDomain(Domain::DP); sim.setSolverType(Solver::Type::MNA); - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); +#ifdef WITH_RT + sim.run(10); +#else sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/ShmemDistributedDirect.cpp b/dpsim-villas/examples/cxx/deprecated/ShmemDistributedDirect.cpp similarity index 81% rename from dpsim-villas/examples/cxx/ShmemDistributedDirect.cpp rename to dpsim-villas/examples/cxx/deprecated/ShmemDistributedDirect.cpp index e2708bfea7..cba29ff941 100644 --- a/dpsim-villas/examples/cxx/ShmemDistributedDirect.cpp +++ b/dpsim-villas/examples/cxx/deprecated/ShmemDistributedDirect.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -77,11 +77,25 @@ int main(int argc, char *argv[]) { sim.addLogger(logger); // Map attributes to interface entries - InterfaceShmem intf(in, out); - intf.importAttribute(evs->mVoltageRef, 0); + const auto shmemConfig = fmt::format( + R"STRING( + {{ + "type": "shmem", + "in": {{ + "name": "{}" + }}, + "out": {{ + "name": "{}" + }}, + "queuelen": 1024 + }})STRING", + in, out); + + auto intf = std::make_shared(shmemConfig); + intf->importAttribute(evs->mVoltageRef, 0, true); auto evsAttrMinus = evs->mIntfCurrent->deriveCoeff(0, 0); - intf.exportAttribute(evsAttrMinus, 0); - sim.addInterface(std::shared_ptr(&intf)); + intf->exportAttribute(evsAttrMinus, 0, true); + sim.addInterface(intf); MatrixComp initialEvsCurrent = MatrixComp::Zero(1, 1); initialEvsCurrent(0, 0) = Complex(5, 0); @@ -122,14 +136,28 @@ int main(int argc, char *argv[]) { sim.addLogger(logger); // Map attributes to interface entries - InterfaceShmem intf(in, out); - intf.importAttribute(ecs->mCurrentRef, 0); + const auto shmemConfig = fmt::format( + R"STRING( + {{ + "type": "shmem", + "in": {{ + "name": "{}" + }}, + "out": {{ + "name": "{}" + }}, + "queuelen": 1024 + }})STRING", + in, out); + + auto intf = std::make_shared(shmemConfig); + intf->importAttribute(ecs->mCurrentRef, 0, true); //intf.exportComplex(ecs->mIntfVoltage->coeff(0, 0), 0); - intf.exportAttribute( + intf->exportAttribute( ecs->mIntfVoltage->deriveCoeff(0, 0)->deriveScaled( Complex(-1., 0)), - 0); - sim.addInterface(std::shared_ptr(&intf)); + 0, true); + sim.addInterface(intf); sim.run(); } diff --git a/dpsim-villas/examples/cxx/ShmemDistributedReference.cpp b/dpsim-villas/examples/cxx/deprecated/ShmemDistributedReference.cpp similarity index 100% rename from dpsim-villas/examples/cxx/ShmemDistributedReference.cpp rename to dpsim-villas/examples/cxx/deprecated/ShmemDistributedReference.cpp diff --git a/dpsim-villas/examples/cxx/ShmemDistributedVillas.cpp b/dpsim-villas/examples/cxx/deprecated/ShmemDistributedVillas.cpp similarity index 74% rename from dpsim-villas/examples/cxx/ShmemDistributedVillas.cpp rename to dpsim-villas/examples/cxx/deprecated/ShmemDistributedVillas.cpp index 3051c51bed..651d3b309b 100644 --- a/dpsim-villas/examples/cxx/ShmemDistributedVillas.cpp +++ b/dpsim-villas/examples/cxx/deprecated/ShmemDistributedVillas.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -27,7 +27,21 @@ int main(int argc, char *argv[]) { out = "/villas1-out"; } - InterfaceShmem intf(in, out, nullptr); + const auto shmemConfig = fmt::format( + R"STRING( + {{ + "type": "shmem", + "in": {{ + "name": "{}" + }}, + "out": {{ + "name": "{}" + }}, + "queuelen": 1024 + }})STRING", + in, out); + + auto intf = std::make_shared(shmemConfig); if (String(argv[1]) == "0") { // Nodes @@ -49,15 +63,16 @@ int main(int argc, char *argv[]) { // Parameters evs->setParameters(Complex(0, 0)); - vs->setParameters(Complex(10000, 0), 1); + vs->setParameters(Complex(10000, 0), -1, 1e9); l1->setParameters(0.1); r1->setParameters(1); comps = SystemComponentList{evs, vs, l1, r1}; nodes = SystemNodeList{SimNode::GND, n1, n2, n3}; - intf.importAttribute(evs->mVoltageRef, 0); - intf.exportAttribute(evs->mIntfCurrent->deriveCoeff(0, 0), 0); + intf->importAttribute(evs->mVoltageRef, 0, true); + intf->exportAttribute(evs->mIntfCurrent->deriveCoeff(0, 0), 0, + true); } else if (String(argv[1]) == "1") { // Nodes @@ -85,8 +100,9 @@ int main(int argc, char *argv[]) { comps = SystemComponentList{ecs, sw, r2A, r2B}; nodes = SystemNodeList{SimNode::GND, n4, n5}; - intf.importAttribute(ecs->mCurrentRef, 0); - intf.exportAttribute(ecs->mIntfVoltage->deriveCoeff(0, 0), 0); + intf->importAttribute(ecs->mCurrentRef, 0, true); + intf->exportAttribute(ecs->mIntfVoltage->deriveCoeff(0, 0), 0, + true); } else { std::cerr << "invalid test number" << std::endl; std::exit(1); @@ -97,11 +113,15 @@ int main(int argc, char *argv[]) { auto sys = SystemTopology(50, nodes, comps); +#ifdef WITH_RT RealTimeSimulation sim(simName + argv[1]); +#else + Simulation sim(simName + argv[1]); +#endif sim.setSystem(sys); sim.setTimeStep(timeStep); sim.setFinalTime(20); - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); if (String(argv[1]) == "1") { auto evt = SwitchEvent::make( @@ -110,7 +130,11 @@ int main(int argc, char *argv[]) { sim.addEvent(evt); } +#ifdef WITH_RT + sim.run(10); +#else sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/ShmemExample.cpp b/dpsim-villas/examples/cxx/deprecated/ShmemExample.cpp similarity index 78% rename from dpsim-villas/examples/cxx/ShmemExample.cpp rename to dpsim-villas/examples/cxx/deprecated/ShmemExample.cpp index 7f8f942155..39a32c8c74 100644 --- a/dpsim-villas/examples/cxx/ShmemExample.cpp +++ b/dpsim-villas/examples/cxx/deprecated/ShmemExample.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -44,24 +44,32 @@ int main(int argc, char *argv[]) { auto sys = SystemTopology(50, SystemNodeList{SimNode::GND, n1, n2, n3, n4}, SystemComponentList{evs, rs, rl, ll, rL}); -#ifdef REALTIME +#ifdef WITH_RT RealTimeSimulation sim(simName); - sim.setSystem(sys); - sim.setTimeStep(timeStep); - sim.setFinalTime(1.0); - InterfaceShmem intf("/villas1-in", "/villas1-out", nullptr, false); #else Simulation sim(simName); +#endif sim.setSystem(sys); sim.setTimeStep(timeStep); sim.setFinalTime(1.0); - InterfaceShmem intf("/villas1-in", "/villas1-out"); -#endif + + std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "villas1-in" + }, + "out": { + "name": "villas1-out" + } + })STRING"; + + auto intf = std::make_shared(shmemConfig); // Interface - intf.importAttribute(evs->mVoltageRef, 0); - intf.exportAttribute(evs->mIntfCurrent->deriveCoeff(0, 0), 0); - sim.addInterface(std::shared_ptr(&intf)); + intf->importAttribute(evs->mVoltageRef, 0, true); + intf->exportAttribute(evs->mIntfCurrent->deriveCoeff(0, 0), 0, true); + sim.addInterface(intf); // Logger auto logger = DataLogger::make(simName); @@ -73,7 +81,11 @@ int main(int argc, char *argv[]) { logger->logAttribute("i_evs", evs->mIntfCurrent, 1, 1); sim.addLogger(logger); +#ifdef WITH_RT + sim.run(10); +#else sim.run(); +#endif //std::ofstream of("task_dependencies.svg"); //sim.dependencyGraph().render(of); diff --git a/dpsim-villas/examples/cxx/Shmem_CIGRE_MV_PowerFlowTest.cpp b/dpsim-villas/examples/cxx/deprecated/Shmem_CIGRE_MV_PowerFlowTest.cpp similarity index 69% rename from dpsim-villas/examples/cxx/Shmem_CIGRE_MV_PowerFlowTest.cpp rename to dpsim-villas/examples/cxx/deprecated/Shmem_CIGRE_MV_PowerFlowTest.cpp index db15186e05..9dd26974d8 100644 --- a/dpsim-villas/examples/cxx/Shmem_CIGRE_MV_PowerFlowTest.cpp +++ b/dpsim-villas/examples/cxx/deprecated/Shmem_CIGRE_MV_PowerFlowTest.cpp @@ -1,13 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include -#include +#include using namespace std; using namespace DPsim; using namespace CPS; -using namespace CPS::CIM; /* * This example runs the powerflow for the CIGRE MV benchmark system (neglecting the tap changers of the transformers) @@ -27,20 +25,37 @@ int main(int argc, char **argv) { String simName = "Shmem_CIGRE_MV_PowerFlowTest"; CPS::Real system_freq = 50; - CIM::Reader reader(simName, CPS::Logger::Level::debug, - CPS::Logger::Level::off); + CPS::CIM::Reader reader(simName, CPS::Logger::Level::debug, + CPS::Logger::Level::off); SystemTopology sys = reader.loadCIM(system_freq, filenames, CPS::Domain::SP); +#ifdef WITH_RT RealTimeSimulation sim(simName, args.logLevel); +#else + Simulation sim(simName, args.logLevel); +#endif sim.setSystem(sys); sim.setTimeStep(args.timeStep); sim.setFinalTime(args.duration); sim.setDomain(args.solver.domain); sim.setSolverType(args.solver.type); - InterfaceShmem intf("/dpsim1-villas", "/villas-dpsim1"); + + const std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "dpsim1-villas" + }, + "out": { + "name": "villas-dpsim1" + }, + "queuelen": 1024 + })STRING"; + + auto intf = std::make_shared(shmemConfig); // Register exportable node voltages - UInt o = 0; + [[maybe_unused]] UInt o = 0; for (auto n : sys.mNodes) { UInt i; if (sscanf(n->name().c_str(), "N%u", &i) != 1) { @@ -57,15 +72,19 @@ int main(int argc, char **argv) { std::cout << "Signal " << (i * 2) + 1 << ": Phas " << n->name() << std::endl; - intf.exportReal(v->deriveMag(), (i * 2) + 0); + intf->exportAttribute(v->deriveMag(), (i * 2) + 0, true); o++; - intf.exportReal(v->derivePhase(), (i * 2) + 1); + intf->exportAttribute(v->derivePhase(), (i * 2) + 1, true); o++; } - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); - sim.run(std::chrono::seconds(5)); +#ifdef WITH_RT + sim.run(10); +#else + sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp b/dpsim-villas/examples/cxx/deprecated/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp similarity index 74% rename from dpsim-villas/examples/cxx/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp rename to dpsim-villas/examples/cxx/deprecated/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp index 4aab9918d7..7f4e0a4198 100644 --- a/dpsim-villas/examples/cxx/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp +++ b/dpsim-villas/examples/cxx/deprecated/Shmem_CIGRE_MV_PowerFlowTest_LoadProfiles.cpp @@ -1,16 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include -#include -#include +#include #include #include +#include using namespace std; using namespace DPsim; using namespace CPS; -using namespace CPS::CIM; /* * This example runs the powerflow for the CIGRE MV benchmark system (neglecting the tap changers of the transformers) @@ -49,29 +47,46 @@ int main(int argc, char **argv) { String simName = "Shmem_CIGRE-MV-NoTap"; CPS::Real system_freq = 50; - CIM::Reader reader(simName, CPS::Logger::Level::debug, - CPS::Logger::Level::off); + CPS::CIM::Reader reader(simName, CPS::Logger::Level::debug, + CPS::Logger::Level::off); SystemTopology sys = reader.loadCIM(system_freq, filenames, CPS::Domain::SP); - CSVReader csvreader(simName, loadProfilePath, assignList, - CPS::Logger::Level::info); + CPS::CSVReader csvreader(simName, loadProfilePath, assignList, + CPS::Logger::Level::info); csvreader.assignLoadProfile(sys, 0, args.timeStep, args.duration, - CSVReader::Mode::MANUAL); + CPS::CSVReader::Mode::MANUAL); +#ifdef WITH_RT RealTimeSimulation sim(simName, args.logLevel); +#else + Simulation sim(simName, args.logLevel); +#endif sim.setSystem(sys); sim.setTimeStep(args.timeStep); sim.setFinalTime(args.duration); sim.setDomain(args.solver.domain); sim.setSolverType(args.solver.type); - InterfaceShmem intf("/dpsim1-villas", "/villas-dpsim1"); + + const std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "dpsim1-villas" + }, + "out": { + "name": "villas-dpsim1" + }, + "queuelen": 1024 + })STRING"; + + auto intf = std::make_shared(shmemConfig); ofstream villas_conf; villas_conf.open("villas_sent_data.conf"); // Register exportable node voltages - string list_varnames[sys.mNodes.size() * 2]; - UInt o = 0; + std::vector list_varnames(sys.mNodes.size() * 2); + [[maybe_unused]] UInt o = 0; for (auto n : sys.mNodes) { UInt i; if (sscanf(n->name().c_str(), "N%u", &i) != 1) { @@ -88,9 +103,9 @@ int main(int argc, char **argv) { std::cout << "Signal " << (i * 2) + 1 << ": Phas " << n->name() << std::endl; - intf.exportReal(v->deriveMag(), (i * 2) + 0); + intf->exportAttribute(v->deriveMag(), (i * 2) + 0, true); o++; - intf.exportReal(v->derivePhase(), (i * 2) + 1); + intf->exportAttribute(v->derivePhase(), (i * 2) + 1, true); o++; list_varnames[(i * 2) + 0] = n->name() + ".V.mag"; @@ -102,9 +117,13 @@ int main(int argc, char **argv) { } villas_conf.close(); - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); - sim.run(std::chrono::seconds(5)); +#ifdef WITH_RT + sim.run(10); +#else + sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/Shmem_WSCC-9bus.cpp b/dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus.cpp similarity index 58% rename from dpsim-villas/examples/cxx/Shmem_WSCC-9bus.cpp rename to dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus.cpp index bd53e098b9..fdbc0a8fd1 100644 --- a/dpsim-villas/examples/cxx/Shmem_WSCC-9bus.cpp +++ b/dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include using namespace DPsim; using namespace CPS::DP; @@ -19,10 +19,15 @@ int main(int argc, char *argv[]) { String simName = "Shmem_WSCC-9bus"; - CIMReader reader(simName, CPS::Logger::Level::info, CPS::Logger::Level::info); + CPS::CIM::Reader reader(simName, CPS::Logger::Level::info, + CPS::Logger::Level::info); SystemTopology sys = reader.loadCIM(60, filenames); +#ifdef WITH_RT RealTimeSimulation sim(simName, CPS::Logger::Level::debug); +#else + Simulation sim(simName, CPS::Logger::Level::debug); +#endif sim.setSystem(sys); sim.setTimeStep(0.001); sim.setFinalTime(120); @@ -30,21 +35,37 @@ int main(int argc, char *argv[]) { sim.setSolverType(Solver::Type::MNA); sim.doInitFromNodesAndTerminals(true); - InterfaceShmem intf("/dpsim-villas", "/villas-dpsim"); + const std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "dpsim-villas" + }, + "out": { + "name": "villas-dpsim" + }, + "queuelen": 1024 + })STRING"; + + auto intf = std::make_shared(shmemConfig); // Register exportable node voltages UInt o = 0; for (auto n : sys.mNodes) { auto v = n->attributeTyped("v"); - intf.exportReal(v->deriveMag(), o + 0); - intf.exportReal(v->derivePhase(), o + 1); + intf->exportAttribute(v->deriveMag(), o + 0, true); + intf->exportAttribute(v->derivePhase(), o + 1, true); o += 2; } - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); +#ifdef WITH_RT + sim.run(10); +#else sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/Shmem_WSCC-9bus_Ctrl.cpp b/dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus_Ctrl.cpp similarity index 75% rename from dpsim-villas/examples/cxx/Shmem_WSCC-9bus_Ctrl.cpp rename to dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus_Ctrl.cpp index 51fa3a2eb5..ecf6ac2026 100644 --- a/dpsim-villas/examples/cxx/Shmem_WSCC-9bus_Ctrl.cpp +++ b/dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus_Ctrl.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include using namespace DPsim; using namespace CPS::DP::Ph1; @@ -59,7 +59,11 @@ int main(int argc, char *argv[]) { load->mActivePower->setReference(filtP->mOutput); sys.mComponents.push_back(filtP); +#ifdef WITH_RT RealTimeSimulation sim(simName, CPS::Logger::Level::off); +#else + Simulation sim(simName, CPS::Logger::Level::off); +#endif sim.setSystem(sys); sim.setTimeStep(args.timeStep); sim.setFinalTime(args.duration); @@ -67,7 +71,19 @@ int main(int argc, char *argv[]) { sim.setSolverType(Solver::Type::MNA); sim.doInitFromNodesAndTerminals(true); - InterfaceShmem intf("/dpsim1-villas", "/villas-dpsim1", nullptr, false); + const std::string shmemConfig = R"STRING( + { + "type": "shmem", + "in": { + "name": "dpsim1-villas" + }, + "out": { + "name": "villas-dpsim1" + }, + "queuelen": 1024 + })STRING"; + + auto intf = std::make_shared(shmemConfig); auto logger = DataLogger::make(simName); @@ -91,9 +107,9 @@ int main(int argc, char *argv[]) { std::cout << "Signal " << (i * 2) + 1 << ": Phas " << n->name() << std::endl; - intf.exportReal(v->deriveMag(), (i * 2) + 0); + intf->exportAttribute(v->deriveMag(), (i * 2) + 0, true); o++; - intf.exportReal(v->derivePhase(), (i * 2) + 1); + intf->exportAttribute(v->derivePhase(), (i * 2) + 1, true); o++; logger->logAttribute(fmt::format("mag_{}", i), v->deriveMag()); @@ -103,15 +119,24 @@ int main(int argc, char *argv[]) { logger->logAttribute("v3", sys.node("BUS3")->mVoltage); // TODO gain by 20e8 - filtP->setInput(intf.importReal(0)); - filtP_profile->setInput(intf.importReal(1)); + auto filtPInput = CPS::AttributeDynamic::make(0.0); + intf->importAttribute(filtPInput, 0, true); + filtP->setInput(filtPInput); + + auto filtPProfileInput = CPS::AttributeDynamic::make(0.0); + intf->importAttribute(filtPProfileInput, 1, true); + filtP_profile->setInput(filtPProfileInput); - intf.exportReal(load->attributeTyped("P"), o++); - intf.exportReal(load_profile->attributeTyped("P"), o++); + intf->exportAttribute(load->attributeTyped("P"), o++, true); + intf->exportAttribute(load_profile->attributeTyped("P"), o++, true); - sim.addInterface(std::shared_ptr(&intf)); + sim.addInterface(intf); sim.addLogger(logger); - sim.run(args.startTime); +#ifdef WITH_RT + sim.run(10); +#else + sim.run(); +#endif return 0; } diff --git a/dpsim-villas/examples/cxx/Shmem_WSCC-9bus_CtrlDist.cpp b/dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus_CtrlDist.cpp similarity index 62% rename from dpsim-villas/examples/cxx/Shmem_WSCC-9bus_CtrlDist.cpp rename to dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus_CtrlDist.cpp index 114c99a03a..809a66c157 100644 --- a/dpsim-villas/examples/cxx/Shmem_WSCC-9bus_CtrlDist.cpp +++ b/dpsim-villas/examples/cxx/deprecated/Shmem_WSCC-9bus_CtrlDist.cpp @@ -4,8 +4,7 @@ #include #include -#include -#include +#include using namespace DPsim; using namespace CPS; @@ -16,6 +15,22 @@ int main(int argc, char *argv[]) { CommandLineArgs args(argc, argv, "Shmem_WSCC-9bus_CtrlDist", 0.001, 20, 60); + auto makeShmemConfig = [](const String &inName, const String &outName) { + return fmt::format( + R"STRING( + {{ + "type": "shmem", + "in": {{ + "name": "{}" + }}, + "out": {{ + "name": "{}" + }}, + "queuelen": 1024 + }})STRING", + inName, outName); + }; + if (args.scenario == 0) { // Find CIM files std::list filenames; @@ -28,8 +43,8 @@ int main(int argc, char *argv[]) { filenames = args.positionalPaths(); } - CIM::Reader reader(args.name, CPS::Logger::Level::info, - CPS::Logger::Level::info); + CPS::CIM::Reader reader(args.name, CPS::Logger::Level::info, + CPS::Logger::Level::info); SystemTopology sys = reader.loadCIM(args.sysFreq, filenames); // Extend system with controllable load (Profile) @@ -44,7 +59,11 @@ int main(int argc, char *argv[]) { ecs->connect({sys.node("BUS4"), DP::SimNode::GND}); sys.mComponents.push_back(ecs); +#ifdef WITH_RT RealTimeSimulation sim(args.name + "_1", CPS::Logger::Level::debug); +#else + Simulation sim(args.name + "_1", CPS::Logger::Level::debug); +#endif sim.setSystem(sys); sim.setTimeStep(args.timeStep); sim.setFinalTime(args.duration); @@ -52,10 +71,12 @@ int main(int argc, char *argv[]) { sim.setSolverType(Solver::Type::MNA); sim.doInitFromNodesAndTerminals(true); - InterfaceShmem intf1("/dpsim01", "/dpsim10", nullptr, false); - InterfaceShmem intf2("/dpsim1-villas", "/villas-dpsim1", nullptr, false); - sim.addInterface(std::shared_ptr(&intf1)); - sim.addInterface(std::shared_ptr(&intf2)); + auto intf1 = std::make_shared( + makeShmemConfig("dpsim01", "dpsim10")); + auto intf2 = std::make_shared( + makeShmemConfig("dpsim1-villas", "villas-dpsim1")); + sim.addInterface(intf1); + sim.addInterface(intf2); // Controllers and filter std::vector coefficients_profile = std::vector(2000, 1. / 2000); @@ -66,11 +87,14 @@ int main(int argc, char *argv[]) { sys.mComponents.push_back(filtP_profile); // Register interface current source and voltage drop - intf1.importAttribute(ecs->mCurrentRef, 0); - intf1.exportAttribute(ecs->mIntfVoltage->deriveCoeff(0, 0), 0); + intf1->importAttribute(ecs->mCurrentRef, 0, true); + intf1->exportAttribute(ecs->mIntfVoltage->deriveCoeff(0, 0), 0, + true); // TODO: gain by 20e8 - filtP_profile->setInput(intf2.importReal(0)); + auto filtPProfileInput = CPS::AttributeDynamic::make(0.0); + intf2->importAttribute(filtPProfileInput, 0, true); + filtP_profile->setInput(filtPProfileInput); // Register exportable node voltages for (auto n : sys.mNodes) { @@ -90,11 +114,15 @@ int main(int argc, char *argv[]) { std::cout << "Signal " << (i * 2) + 1 << ": Phas " << n->name() << std::endl; - intf2.exportReal(v->deriveMag(), (i * 2) + 0); - intf2.exportReal(v->derivePhase(), (i * 2) + 1); + intf2->exportAttribute(v->deriveMag(), (i * 2) + 0, true); + intf2->exportAttribute(v->derivePhase(), (i * 2) + 1, true); } - sim.run(args.startTime); +#ifdef WITH_RT + sim.run(10); +#else + sim.run(); +#endif } if (args.scenario == 1) { @@ -120,30 +148,45 @@ int main(int argc, char *argv[]) { auto sys = SystemTopology(args.sysFreq, SystemNodeList{n1}, SystemComponentList{evs, load, filtP}); +#ifdef WITH_RT RealTimeSimulation sim(args.name + "_2"); +#else + Simulation sim(args.name + "_2"); +#endif sim.setSystem(sys); sim.setTimeStep(args.timeStep); sim.setFinalTime(args.duration); - InterfaceShmem intf1("/dpsim10", "/dpsim01", nullptr, false); - sim.addInterface(std::shared_ptr(&intf1)); + auto intf1 = std::make_shared( + makeShmemConfig("dpsim10", "dpsim01")); + sim.addInterface(intf1); - InterfaceShmem intf2("/dpsim2-villas", "/villas-dpsim2", nullptr, false); - sim.addInterface(std::shared_ptr(&intf2)); + auto intf2 = std::make_shared( + makeShmemConfig("dpsim2-villas", "villas-dpsim2")); + sim.addInterface(intf2); // Register voltage source reference and current flowing through source // multiply with -1 to consider passive sign convention - intf1.importAttribute(evs->mVoltageRef, 0); + intf1->importAttribute(evs->mVoltageRef, 0, true); // TODO: invalid sign - intf1.exportAttribute(evs->mIntfCurrent->deriveCoeff(0, 0), 0); + intf1->exportAttribute(evs->mIntfCurrent->deriveCoeff(0, 0), 0, + true); // Register controllable load - filtP->setInput(intf2.importReal(0)); - intf2.exportReal(load->mActivePower, 0); - intf2.exportComplex(load->mIntfVoltage->deriveCoeff(0, 0), 1); - intf2.exportComplex(load->mIntfCurrent->deriveCoeff(0, 0), 2); - - sim.run(args.startTime); + auto filtPInput = CPS::AttributeDynamic::make(0.0); + intf2->importAttribute(filtPInput, 0, true); + filtP->setInput(filtPInput); + intf2->exportAttribute(load->mActivePower, 0, true); + intf2->exportAttribute(load->mIntfVoltage->deriveCoeff(0, 0), 1, + true); + intf2->exportAttribute(load->mIntfCurrent->deriveCoeff(0, 0), 2, + true); + +#ifdef WITH_RT + sim.run(10); +#else + sim.run(); +#endif } return 0; diff --git a/dpsim-villas/include/dpsim-villas/Config.h.in b/dpsim-villas/include/dpsim-villas/Config.h.in new file mode 100644 index 0000000000..92d073266e --- /dev/null +++ b/dpsim-villas/include/dpsim-villas/Config.h.in @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#ifndef DPSIM_VILLAS_CONFIG_H +#define DPSIM_VILLAS_CONFIG_H + +#define DPSIM_VILLAS_VERSION "@PROJECT_VERSION@" + +// Features +#cmakedefine WITH_RT +#cmakedefine WITH_VILLAS +#cmakedefine WITH_CIM +#cmakedefine WITH_PYBIND +#cmakedefine WITH_SUNDIALS +#cmakedefine WITH_OPENMP +#cmakedefine WITH_CUDA +#cmakedefine WITH_CUDA_SPARSE +#cmakedefine WITH_MAGMA +#cmakedefine WITH_KLU +#cmakedefine WITH_MNASOLVERPLUGIN +#cmakedefine WITH_JSON +#cmakedefine CGMES_BUILD + +#cmakedefine HAVE_GETOPT +#cmakedefine HAVE_TIMERFD + +#endif diff --git a/dpsim-villas/include/dpsim-villas/Interfaces.h b/dpsim-villas/include/dpsim-villas/Interfaces.h new file mode 100644 index 0000000000..4668785406 --- /dev/null +++ b/dpsim-villas/include/dpsim-villas/Interfaces.h @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include + +#include +#include diff --git a/dpsim-villas/src/CMakeLists.txt b/dpsim-villas/src/CMakeLists.txt index 654414c0b7..ea5c2523ec 100644 --- a/dpsim-villas/src/CMakeLists.txt +++ b/dpsim-villas/src/CMakeLists.txt @@ -5,6 +5,25 @@ set(DPSIM_VILLAS_SOURCES ) add_library(dpsim-villas ${DPSIM_VILLAS_SOURCES}) -target_link_libraries(dpsim-villas PUBLIC dpsim ${VILLASNODE_LIBRARIES} pthread) + +if(NOT VILLASNODE_LIBRARIES) + message(FATAL_ERROR "villas-node is required when building DPsim with VILLAS support.") +endif() + +if(NOT VILLASCOMMON_LIBRARIES) + message(FATAL_ERROR "villas-common is required when building DPsim with VILLAS support.") +endif() + +set(DPSIM_VILLAS_LIBRARIES + dpsim + ${VILLASNODE_LIBRARIES} + ${VILLASCOMMON_LIBRARIES} + pthread +) +if(VILLASFPGA_LIBRARIES) + list(APPEND DPSIM_VILLAS_LIBRARIES ${VILLASFPGA_LIBRARIES}) +endif() + +target_link_libraries(dpsim-villas PUBLIC ${DPSIM_VILLAS_LIBRARIES}) target_include_directories(dpsim-villas PUBLIC ../include ${VILLASNODE_INCLUDE_DIRS}) target_compile_options(dpsim-villas PUBLIC ${DPSIM_CXX_FLAGS}) diff --git a/dpsim-villas/src/InterfaceWorkerVillas.cpp b/dpsim-villas/src/InterfaceWorkerVillas.cpp index 2a99ac6a74..3faefa82b3 100644 --- a/dpsim-villas/src/InterfaceWorkerVillas.cpp +++ b/dpsim-villas/src/InterfaceWorkerVillas.cpp @@ -362,9 +362,9 @@ void InterfaceWorkerVillas::writeValuesToEnv( sample_decref(sample); } catch (const std::exception &) { /* We need to at least send something, so determine where exactly the - * timer expired and either resend the last successfully sent sample or - * just try to send this one again. - * TODO: can this be handled better? */ + * timer expired and either resend the last successfully sent sample or + * just try to send this one again. + * TODO: can this be handled better? */ if (!done) sample = mLastSample; @@ -520,7 +520,8 @@ void InterfaceWorkerVillas::configureImport(UInt attributeId, mImports.emplace_back( [idx, log](Sample *smp) -> AttributeBase::Ptr { if (idx >= smp->length) { - log->error("incomplete data received from InterfaceVillas"); + SPDLOG_LOGGER_ERROR( + log, "incomplete data received from InterfaceVillas"); return nullptr; } return AttributePointer( @@ -533,7 +534,8 @@ void InterfaceWorkerVillas::configureImport(UInt attributeId, mImports.emplace_back( [idx, log](Sample *smp) -> AttributeBase::Ptr { if (idx >= smp->length) { - log->error("incomplete data received from InterfaceVillas"); + SPDLOG_LOGGER_ERROR( + log, "incomplete data received from InterfaceVillas"); return nullptr; } return AttributePointer( @@ -546,7 +548,8 @@ void InterfaceWorkerVillas::configureImport(UInt attributeId, mImports.emplace_back( [idx, log](Sample *smp) -> AttributeBase::Ptr { if (idx >= smp->length) { - log->error("incomplete data received from InterfaceVillas"); + SPDLOG_LOGGER_ERROR( + log, "incomplete data received from InterfaceVillas"); return nullptr; } return AttributePointer( @@ -559,7 +562,8 @@ void InterfaceWorkerVillas::configureImport(UInt attributeId, mImports.emplace_back( [idx, log](Sample *smp) -> AttributeBase::Ptr { if (idx >= smp->length) { - log->error("incomplete data received from InterfaceVillas"); + SPDLOG_LOGGER_ERROR( + log, "incomplete data received from InterfaceVillas"); return nullptr; } return AttributePointer( diff --git a/dpsim/CMakeLists.txt b/dpsim/CMakeLists.txt index d821891211..37ae751479 100644 --- a/dpsim/CMakeLists.txt +++ b/dpsim/CMakeLists.txt @@ -11,10 +11,28 @@ set(DPSIM_INCLUDE_DIRS add_subdirectory(src) if(WITH_PYBIND) - set(DPSIMPY_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/Include/dpsim/pybind) + set(DPSIMPY_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include/dpsim/pybind) add_subdirectory(src/pybind) endif() if(DPSIM_BUILD_EXAMPLES) add_subdirectory(examples) endif() + +file(GLOB_RECURSE HEADER_FILES include/*.h) + +target_sources(dpsim PUBLIC + FILE_SET public_headers + TYPE HEADERS + BASE_DIRS include + FILES "${HEADER_FILES}" +) + +install(TARGETS dpsim + EXPORT dpsim + FILE_SET public_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/dpsim/examples/cxx/CIM/DP_WSCC_9bus_split_decoupled.cpp b/dpsim/examples/cxx/CIM/DP_WSCC_9bus_split_decoupled.cpp index 60c4a5702f..9fc0101a64 100644 --- a/dpsim/examples/cxx/CIM/DP_WSCC_9bus_split_decoupled.cpp +++ b/dpsim/examples/cxx/CIM/DP_WSCC_9bus_split_decoupled.cpp @@ -16,7 +16,8 @@ using namespace DPsim; using namespace CPS; -String decoupleLine(SystemTopology &sys, const String &lineName, const String &node1, const String node2) { +String decoupleLine(SystemTopology &sys, const String &lineName, + const String &node1, const String node2) { auto origLine = sys.component(lineName); Real Rline = origLine->attributeTyped("R_series")->get(); Real Lline = origLine->attributeTyped("L_series")->get(); @@ -27,9 +28,8 @@ String decoupleLine(SystemTopology &sys, const String &lineName, const String &n String dline_name = "dline_" + node1 + "_" + node2; auto line = Signal::DecouplingLine::make( - "dline_" + node1 + "_" + node2, sys.node(node1), - sys.node(node2), Rline, Lline, Cline, Logger::Level::debug - ); + "dline_" + node1 + "_" + node2, sys.node(node1), + sys.node(node2), Rline, Lline, Cline, Logger::Level::debug); sys.addComponent(line); sys.addComponents(line->getLineComponents()); @@ -43,10 +43,11 @@ void doSim(String &name, SystemTopology &sys, Int threads) { // logger->logAttribute("BUS5.v", sys.node("BUS5")->attribute("v")); // logger->logAttribute("BUS6.v", sys.node("BUS6")->attribute("v")); // logger->logAttribute("BUS8.v", sys.node("BUS8")->attribute("v")); - for (Int bus = 1; bus <= 9; bus++) { + for (Int bus = 1; bus <= 9; bus++) { String attrName = "v" + std::to_string(bus); String nodeName = "BUS" + std::to_string(bus); - logger->logAttribute(attrName, sys.node(nodeName)->attribute("v")); + logger->logAttribute(attrName, + sys.node(nodeName)->attribute("v")); } Simulation sim(name, Logger::Level::debug); @@ -72,8 +73,7 @@ int main(int argc, char *argv[]) { std::list filenames; filenames = DPsim::Utils::findFiles( - {"WSCC-09_DI.xml", "WSCC-09_EQ.xml", "WSCC-09_SV.xml", - "WSCC-09_TP.xml"}, + {"WSCC-09_DI.xml", "WSCC-09_EQ.xml", "WSCC-09_SV.xml", "WSCC-09_TP.xml"}, "build/_deps/cim-data-src/WSCC-09/WSCC-09", "CIMPATH"); Int numThreads = 0; @@ -84,25 +84,30 @@ int main(int argc, char *argv[]) { if (args.options.find("seq") != args.options.end()) numSeq = args.getOptionInt("seq"); - std::cout << "Simulate with " << numThreads - << " threads, sequence number " << numSeq << std::endl; + std::cout << "Simulate with " << numThreads << " threads, sequence number " + << numSeq << std::endl; // Monolithic Simulation String simNameMonolithic = "WSCC-9bus_monolithic_DP"; Logger::setLogDir("logs/" + simNameMonolithic); - CIM::Reader readerMonolithic(simNameMonolithic, Logger::Level::debug, Logger::Level::debug); + CIM::Reader readerMonolithic(simNameMonolithic, Logger::Level::debug, + Logger::Level::debug); SystemTopology systemMonolithic = readerMonolithic.loadCIM(60, filenames, Domain::DP, PhaseType::Single, - CPS::GeneratorType::IdealVoltageSource); + CPS::GeneratorType::IdealVoltageSource); doSim(simNameMonolithic, systemMonolithic, 0); // Decoupled Simulation - String simNameDecoupled = "WSCC_9bus_split_decoupled_DP_" + std::to_string(numThreads) + "_" + std::to_string(numSeq); + String simNameDecoupled = "WSCC_9bus_split_decoupled_DP_" + + std::to_string(numThreads) + "_" + + std::to_string(numSeq); Logger::setLogDir("logs/" + simNameDecoupled); - CIM::Reader readerDecoupled(simNameDecoupled, Logger::Level::debug, Logger::Level::debug); - SystemTopology systemDecoupled = readerDecoupled.loadCIM(60, filenames, Domain::DP, PhaseType::Single, - CPS::GeneratorType::IdealVoltageSource); + CIM::Reader readerDecoupled(simNameDecoupled, Logger::Level::debug, + Logger::Level::debug); + SystemTopology systemDecoupled = + readerDecoupled.loadCIM(60, filenames, Domain::DP, PhaseType::Single, + CPS::GeneratorType::IdealVoltageSource); String dline_75 = decoupleLine(systemDecoupled, "LINE75", "BUS5", "BUS7"); // decouple_line(system, "LINE78", "BUS7", "BUS8"); diff --git a/dpsim/examples/cxx/CIM/EMT_WSCC-9bus_FullOrderSG.cpp b/dpsim/examples/cxx/CIM/EMT_WSCC-9bus_FullOrderSG.cpp index d7a3fd0ae1..b4522e8605 100644 --- a/dpsim/examples/cxx/CIM/EMT_WSCC-9bus_FullOrderSG.cpp +++ b/dpsim/examples/cxx/CIM/EMT_WSCC-9bus_FullOrderSG.cpp @@ -25,8 +25,10 @@ int main(int argc, char *argv[]) { std::list filenames; CommandLineArgs args(argc, argv); if (argc <= 1) { - filenames = - Utils::findFiles({"WSCC-09_Dyn_Full_DI.xml", "WSCC-09_Dyn_Full_EQ.xml", "WSCC-09_Dyn_Full_SV.xml", "WSCC-09_Dyn_Full_TP.xml"}, "build/_deps/cim-data-src/WSCC-09/WSCC-09_Dyn_Full", "CIMPATH"); + filenames = Utils::findFiles( + {"WSCC-09_Dyn_Full_DI.xml", "WSCC-09_Dyn_Full_EQ.xml", + "WSCC-09_Dyn_Full_SV.xml", "WSCC-09_Dyn_Full_TP.xml"}, + "build/_deps/cim-data-src/WSCC-09/WSCC-09_Dyn_Full", "CIMPATH"); timeStep = 10e-6; finalTime = 0.1; } else { diff --git a/dpsim/examples/cxx/CIM/EMT_WSCC_9bus_split_decoupled.cpp b/dpsim/examples/cxx/CIM/EMT_WSCC_9bus_split_decoupled.cpp index 2b39f66ce2..9827d378c6 100644 --- a/dpsim/examples/cxx/CIM/EMT_WSCC_9bus_split_decoupled.cpp +++ b/dpsim/examples/cxx/CIM/EMT_WSCC_9bus_split_decoupled.cpp @@ -16,7 +16,8 @@ using namespace DPsim; using namespace CPS; -String decoupleLine(SystemTopology &sys, const String &lineName, const String &node1, const String node2) { +String decoupleLine(SystemTopology &sys, const String &lineName, + const String &node1, const String node2) { auto origLine = sys.component(lineName); Matrix Rline = origLine->attributeTyped("R_series")->get(); Matrix Lline = origLine->attributeTyped("L_series")->get(); @@ -26,18 +27,11 @@ String decoupleLine(SystemTopology &sys, const String &lineName, const String &n String dline_name = "dline_" + node1 + "_" + node2; - auto line = Signal::DecouplingLineEMT::make( - "dline_" + node1 + "_" + node2, - Logger::Level::debug - ); + auto line = Signal::DecouplingLineEMT_Ph3::make( + "dline_" + node1 + "_" + node2, Logger::Level::debug); - Real Rline_scalar = Rline(0,0); - Real Lline_scalar = Lline(0,0); - Real Cline_scalar = Cline(0,0); - - line->setParameters( - sys.node(node1), sys.node(node2), - Rline_scalar, Lline_scalar, Cline_scalar); + line->setParameters(sys.node(node1), + sys.node(node2), Rline, Lline, Cline); sys.addComponent(line); sys.addComponents(line->getLineComponents()); @@ -48,13 +42,17 @@ void doSim(String &name, SystemTopology &sys, Int threads) { // Logging auto logger = DataLogger::make(name); - // logger->logAttribute("BUS5.v", sys.node("BUS5")->attribute("v")); - // logger->logAttribute("BUS6.v", sys.node("BUS6")->attribute("v")); - // logger->logAttribute("BUS8.v", sys.node("BUS8")->attribute("v")); - for (Int bus = 1; bus <= 9; bus++) { + logger->logAttribute("BUS5.v", + sys.node("BUS5")->attribute("v")); + logger->logAttribute("BUS6.v", + sys.node("BUS6")->attribute("v")); + logger->logAttribute("BUS8.v", + sys.node("BUS8")->attribute("v")); + for (Int bus = 1; bus <= 9; bus++) { String attrName = "v" + std::to_string(bus); String nodeName = "BUS" + std::to_string(bus); - logger->logAttribute(attrName, sys.node(nodeName)->attribute("v")); + logger->logAttribute(attrName, + sys.node(nodeName)->attribute("v")); } Simulation sim(name, Logger::Level::debug); @@ -80,8 +78,7 @@ int main(int argc, char *argv[]) { std::list filenames; filenames = DPsim::Utils::findFiles( - {"WSCC-09_DI.xml", "WSCC-09_EQ.xml", "WSCC-09_SV.xml", - "WSCC-09_TP.xml"}, + {"WSCC-09_DI.xml", "WSCC-09_EQ.xml", "WSCC-09_SV.xml", "WSCC-09_TP.xml"}, "build/_deps/cim-data-src/WSCC-09/WSCC-09", "CIMPATH"); Int numThreads = 0; @@ -92,25 +89,30 @@ int main(int argc, char *argv[]) { if (args.options.find("seq") != args.options.end()) numSeq = args.getOptionInt("seq"); - std::cout << "Simulate with " << numThreads - << " threads, sequence number " << numSeq << std::endl; + std::cout << "Simulate with " << numThreads << " threads, sequence number " + << numSeq << std::endl; // Monolithic Simulation String simNameMonolithic = "WSCC-9bus_monolithic_EMT"; Logger::setLogDir("logs/" + simNameMonolithic); - CIM::Reader readerMonolithic(simNameMonolithic, Logger::Level::debug, Logger::Level::debug); + CIM::Reader readerMonolithic(simNameMonolithic, Logger::Level::debug, + Logger::Level::debug); SystemTopology systemMonolithic = readerMonolithic.loadCIM(60, filenames, Domain::EMT, PhaseType::ABC, - CPS::GeneratorType::IdealVoltageSource); + CPS::GeneratorType::IdealVoltageSource); doSim(simNameMonolithic, systemMonolithic, 0); // Decoupled Simulation - String simNameDecoupled = "WSCC_9bus_split_decoupled_EMT_" + std::to_string(numThreads) + "_" + std::to_string(numSeq); + String simNameDecoupled = "WSCC_9bus_split_decoupled_EMT_" + + std::to_string(numThreads) + "_" + + std::to_string(numSeq); Logger::setLogDir("logs/" + simNameDecoupled); - CIM::Reader readerDecoupled(simNameDecoupled, Logger::Level::debug, Logger::Level::debug); - SystemTopology systemDecoupled = readerDecoupled.loadCIM(60, filenames, Domain::EMT, PhaseType::ABC, - CPS::GeneratorType::IdealVoltageSource); + CIM::Reader readerDecoupled(simNameDecoupled, Logger::Level::debug, + Logger::Level::debug); + SystemTopology systemDecoupled = + readerDecoupled.loadCIM(60, filenames, Domain::EMT, PhaseType::ABC, + CPS::GeneratorType::IdealVoltageSource); String dline_75 = decoupleLine(systemDecoupled, "LINE75", "BUS5", "BUS7"); // decouple_line(system, "LINE78", "BUS7", "BUS8"); diff --git a/dpsim/examples/cxx/CIM/WSCC_9bus_mult_coupled.cpp b/dpsim/examples/cxx/CIM/WSCC_9bus_mult_coupled.cpp index fc42ddca98..d3d31597dc 100644 --- a/dpsim/examples/cxx/CIM/WSCC_9bus_mult_coupled.cpp +++ b/dpsim/examples/cxx/CIM/WSCC_9bus_mult_coupled.cpp @@ -89,15 +89,16 @@ void simulateCoupled(std::list filenames, CommandLineArgs &args, // Logging auto logger = DataLogger::make(simName); for (Int cop = 1; cop <= copies; cop++) { - for (Int bus = 1; bus <= 9; bus++) { - String attrName = "v" + std::to_string(bus) + "_" + std::to_string(cop); - String nodeName = "BUS" + std::to_string(bus) + "_" + std::to_string(cop); - if (cop == 1) { - attrName = "v" + std::to_string(bus); - nodeName = "BUS" + std::to_string(bus); - } - logger->logAttribute(attrName, sys.node(nodeName)->attribute("v")); - } + for (Int bus = 1; bus <= 9; bus++) { + String attrName = "v" + std::to_string(bus) + "_" + std::to_string(cop); + String nodeName = "BUS" + std::to_string(bus) + "_" + std::to_string(cop); + if (cop == 1) { + attrName = "v" + std::to_string(bus); + nodeName = "BUS" + std::to_string(bus); + } + logger->logAttribute(attrName, + sys.node(nodeName)->attribute("v")); + } } sim.addLogger(logger); diff --git a/dpsim/examples/cxx/CIM/WSCC_9bus_mult_decoupled.cpp b/dpsim/examples/cxx/CIM/WSCC_9bus_mult_decoupled.cpp index 427981cc5b..2f61d77855 100644 --- a/dpsim/examples/cxx/CIM/WSCC_9bus_mult_decoupled.cpp +++ b/dpsim/examples/cxx/CIM/WSCC_9bus_mult_decoupled.cpp @@ -69,15 +69,16 @@ void simulateDecoupled(std::list filenames, Int copies, Int threads, // Logging auto logger = DataLogger::make(simName); for (Int cop = 1; cop <= copies; cop++) { - for (Int bus = 1; bus <= 9; bus++) { - String attrName = "v" + std::to_string(bus) + "_" + std::to_string(cop); - String nodeName = "BUS" + std::to_string(bus) + "_" + std::to_string(cop); - if (cop == 1) { - attrName = "v" + std::to_string(bus); - nodeName = "BUS" + std::to_string(bus); - } - logger->logAttribute(attrName, sys.node(nodeName)->attribute("v")); - } + for (Int bus = 1; bus <= 9; bus++) { + String attrName = "v" + std::to_string(bus) + "_" + std::to_string(cop); + String nodeName = "BUS" + std::to_string(bus) + "_" + std::to_string(cop); + if (cop == 1) { + attrName = "v" + std::to_string(bus); + nodeName = "BUS" + std::to_string(bus); + } + logger->logAttribute(attrName, + sys.node(nodeName)->attribute("v")); + } } sim.addLogger(logger); diff --git a/dpsim/examples/cxx/CIM/WSCC_9bus_mult_diakoptics.cpp b/dpsim/examples/cxx/CIM/WSCC_9bus_mult_diakoptics.cpp index d89a1fe95f..01e86196a5 100644 --- a/dpsim/examples/cxx/CIM/WSCC_9bus_mult_diakoptics.cpp +++ b/dpsim/examples/cxx/CIM/WSCC_9bus_mult_diakoptics.cpp @@ -90,15 +90,16 @@ void simulateDiakoptics(std::list filenames, Int copies, Int threads, // Logging auto logger = DataLogger::make(simName); for (Int cop = 1; cop <= copies; cop++) { - for (Int bus = 1; bus <= 9; bus++) { - String attrName = "v" + std::to_string(bus) + "_" + std::to_string(cop); - String nodeName = "BUS" + std::to_string(bus) + "_" + std::to_string(cop); - if (cop == 1) { - attrName = "v" + std::to_string(bus); - nodeName = "BUS" + std::to_string(bus); - } - logger->logAttribute(attrName, sys.node(nodeName)->attribute("v")); - } + for (Int bus = 1; bus <= 9; bus++) { + String attrName = "v" + std::to_string(bus) + "_" + std::to_string(cop); + String nodeName = "BUS" + std::to_string(bus) + "_" + std::to_string(cop); + if (cop == 1) { + attrName = "v" + std::to_string(bus); + nodeName = "BUS" + std::to_string(bus); + } + logger->logAttribute(attrName, + sys.node(nodeName)->attribute("v")); + } } sim.addLogger(logger); diff --git a/dpsim/examples/cxx/CMakeLists.txt b/dpsim/examples/cxx/CMakeLists.txt index 11c797f280..fd913843fc 100644 --- a/dpsim/examples/cxx/CMakeLists.txt +++ b/dpsim/examples/cxx/CMakeLists.txt @@ -1,7 +1,7 @@ set(LIBRARIES "dpsim") if(NOT WIN32) - # Needed so CIMParser and arabica (which are first compiled into static libs) + # Needed so CIMParser and Arabica (which are first compiled into static libs) # can be included in the .so set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() @@ -33,8 +33,10 @@ set(CIRCUIT_SOURCES #Circuits/EMT_ResVS_RL_Switch.cpp Circuits/EMT_VSI.cpp Circuits/EMT_PiLine.cpp + Circuits/EMT_DecouplingLine_Ph3.cpp Circuits/EMT_Ph3_R3C1L1CS1_RC_vs_SSN.cpp Circuits/EMT_Ph3_RLC1VS1_RC_vs_SSN.cpp + Circuits/EMT_Ph1_General2TerminalSSN.cpp # EMT examples with PF initialization Circuits/EMT_Slack_PiLine_PQLoad_with_PF_Init.cpp @@ -64,7 +66,6 @@ set(CIRCUIT_SOURCES Circuits/DP_SynGenTrStab_SMIB_Fault.cpp Circuits/EMT_SynGenDQ7odTrapez_SMIB_Fault.cpp Circuits/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault.cpp - Circuits/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_JsonSyngenParams.cpp Circuits/EMT_SynGenDQ7odTrapez_DP_SynGenTrStab_SMIB_Fault.cpp Circuits/EMT_SynGenTrStab_SMIB_Fault.cpp Circuits/SP_SynGenTrStab_SMIB_Fault_KundurExample1.cpp @@ -85,14 +86,19 @@ set(CIRCUIT_SOURCES Circuits/EMT_SMIB_ReducedOrderSGIterative_LoadStep.cpp Circuits/DP_SMIB_ReducedOrderSGIterative_LoadStep.cpp - #3Bus System + # 3Bus System Circuits/SP_SynGenTrStab_3Bus_SteadyState.cpp Circuits/DP_SynGenTrStab_3Bus_SteadyState.cpp Circuits/DP_SynGenTrStab_3Bus_Fault.cpp Circuits/SP_SynGenTrStab_3Bus_Fault.cpp - ) +if(WITH_JSON) + list(APPEND CIRCUIT_SOURCES + Circuits/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault_JsonSyngenParams.cpp + ) +endif() + set(SYNCGEN_SOURCES Components/DP_SynGenDq7odTrapez_SteadyState.cpp Components/DP_SynGenDq7odTrapez_ThreePhFault.cpp @@ -136,6 +142,7 @@ list(APPEND TEST_SOURCES Circuits/DP_SMIB_ReducedOrderSGIterative_LoadStep.cpp Circuits/EMT_Ph3_R3C1L1CS1_RC_vs_SSN.cpp Circuits/EMT_Ph3_RLC1VS1_RC_vs_SSN.cpp + Circuits/EMT_Ph1_General2TerminalSSN.cpp ) if(WITH_SUNDIALS) @@ -161,7 +168,7 @@ if(WITH_RT) endif() if(WITH_CIM) - list(APPEND LIBRARIES libcimpp) + list(APPEND LIBRARIES CIMPP::cimpp) set(CIM_SOURCES CIM/WSCC-9bus_CIM.cpp @@ -173,6 +180,7 @@ if(WITH_CIM) CIM/EMT_WSCC-9bus_FullOrderSG.cpp CIM/EMT_WSCC-9bus_VBR.cpp CIM/DP_WSCC-9bus_IdealVS.cpp + # CIM/SEGURO.cpp # WSCC Reduced Order CIM/SP_WSCC9bus_SGReducedOrderVBR.cpp diff --git a/dpsim/examples/cxx/Circuits/DP_PiLine.cpp b/dpsim/examples/cxx/Circuits/DP_PiLine.cpp index 862b1277a5..5afec41435 100644 --- a/dpsim/examples/cxx/Circuits/DP_PiLine.cpp +++ b/dpsim/examples/cxx/Circuits/DP_PiLine.cpp @@ -61,8 +61,6 @@ void simElements() { auto sys = SystemTopology( 50, SystemNodeList{n1, n2, vn1}, SystemComponentList{vs, res, ind, cap1, cap2, con1, con2, load}); - //SystemComponentList{vs, res, ind, cap1, cap2, load}); - //SystemComponentList{vs, res, ind, load}); // Logging auto logger = DataLogger::make(simName); @@ -162,6 +160,183 @@ void simPiLineDiakoptics() { auto logger = DataLogger::make(simName); logger->logAttribute("v1", n1->attribute("v")); logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", line->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setTearingComponents(sys.mTearComponents); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simElements3ph() { + Real timeStep = 0.00005; + Real finalTime = 1; + String simName = "DP_PiLine_Elements_3ph"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::ABC); + auto n2 = SimNode::make("n2", PhaseType::ABC); + auto vn1 = SimNode::make("vn1", PhaseType::ABC); + + // Components + auto vs = Ph3::VoltageSource::make("v_1"); + vs->setParameters(CPS::Math::polar(100000, 0)); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto res = Ph3::Resistor::make("R_line"); + res->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance)); + auto ind = Ph3::Inductor::make("L_line"); + ind->setParameters(CPS::Math::singlePhaseParameterToThreePhase(inductance)); + auto cap1 = Ph3::Capacitor::make("Cp_1"); + cap1->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(capacitance / 2.)); + auto cap2 = Ph3::Capacitor::make("Cp_2"); + cap2->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(capacitance / 2.)); + auto con1 = Ph3::Resistor::make("Gp_1"); + con1->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(2. / conductance)); + auto con2 = Ph3::Resistor::make("Gp_2"); + con2->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(2. / conductance)); + + auto load = Ph3::Resistor::make("R_load"); + load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); + + // Topology + vs->connect({SimNode::GND, n1}); + res->connect({n1, vn1}); + ind->connect({vn1, n2}); + cap1->connect({n1, SimNode::GND}); + cap2->connect({n2, SimNode::GND}); + con1->connect({n1, SimNode::GND}); + con2->connect({n2, SimNode::GND}); + load->connect({n2, SimNode::GND}); + + auto sys = SystemTopology( + 50, SystemNodeList{n1, n2, vn1}, + SystemComponentList{vs, res, ind, cap1, cap2, con1, con2, load}); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", ind->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simPiLine3ph() { + Real timeStep = 0.00005; + Real finalTime = 1; + String simName = "DP_PiLine_Component_3ph"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::ABC); + auto n2 = SimNode::make("n2", PhaseType::ABC); + + // Components + auto vs = Ph3::VoltageSource::make("v_1"); + vs->setParameters(CPS::Math::polar(100000, 0)); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto line = Ph3::PiLine::make("Line"); + line->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance), + CPS::Math::singlePhaseParameterToThreePhase(inductance), + CPS::Math::singlePhaseParameterToThreePhase(capacitance), + CPS::Math::singlePhaseParameterToThreePhase(conductance)); + + auto load = Ph3::Resistor::make("R_load"); + load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); + + // Topology + vs->connect({SimNode::GND, n1}); + line->connect({n1, n2}); + load->connect({n2, SimNode::GND}); + + auto sys = SystemTopology(50, SystemNodeList{n1, n2}, + SystemComponentList{vs, line, load}); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", line->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simPiLineDiakoptics3ph() { + Real timeStep = 0.00005; + Real finalTime = 0.1; + String simName = "DP_PiLine_Diakoptics_3ph"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::ABC); + auto n2 = SimNode::make("n2", PhaseType::ABC); + + // Components + auto vs = Ph3::VoltageSource::make("v_1"); + vs->setParameters(CPS::Math::polar(100000, 0)); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto line = Ph3::PiLine::make("Line"); + line->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance), + CPS::Math::singlePhaseParameterToThreePhase(inductance), + CPS::Math::singlePhaseParameterToThreePhase(capacitance), + CPS::Math::singlePhaseParameterToThreePhase(conductance)); + + auto load = Ph3::Resistor::make("R_load"); + load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); + + // Topology + vs->connect({SimNode::GND, n1}); + line->connect({n1, n2}); + load->connect({n2, SimNode::GND}); + + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, load}); + sys.addTearComponent(line); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", line->attribute("i_intf")); Simulation sim(simName); sim.setSystem(sys); @@ -177,4 +352,8 @@ int main(int argc, char *argv[]) { simElements(); simPiLine(); simPiLineDiakoptics(); + + simElements3ph(); + simPiLine3ph(); + simPiLineDiakoptics3ph(); } diff --git a/dpsim/examples/cxx/Circuits/DP_VSI.cpp b/dpsim/examples/cxx/Circuits/DP_VSI.cpp index b147dde6b1..b204c0c815 100644 --- a/dpsim/examples/cxx/Circuits/DP_VSI.cpp +++ b/dpsim/examples/cxx/Circuits/DP_VSI.cpp @@ -110,12 +110,14 @@ void DP_Ph1_VSI2_4bus_SampleGrid() { } // Logging auto logger = DataLogger::make(simName); - // currents - /*logger->logAttribute("i_vs", vs->attribute("i_intf")); - logger->logAttribute("i_vsi", vsi->attribute("i_intf")); - logger->logAttribute("i_vsi2", vsi2->attribute("i_intf")); - logger->logAttribute("iload", rload->attribute("i_intf")); - logger->logAttribute("iqload", Lload->attribute("i_intf"));*/ +#if 0 + // Currents + logger->logAttribute("i_vs", vs->attribute("i_intf")); + logger->logAttribute("i_vsi", vsi->attribute("i_intf")); + logger->logAttribute("i_vsi2", vsi2->attribute("i_intf")); + logger->logAttribute("iload", rload->attribute("i_intf")); + logger->logAttribute("iqload", Lload->attribute("i_intf")); +#endif // nodal voltages logger->logAttribute("vBus1", n1->attribute("v")); logger->logAttribute("v_slack", n5->attribute("v")); diff --git a/dpsim/examples/cxx/Circuits/EMT_DecouplingLine_Ph3.cpp b/dpsim/examples/cxx/Circuits/EMT_DecouplingLine_Ph3.cpp new file mode 100644 index 0000000000..dbf43bb272 --- /dev/null +++ b/dpsim/examples/cxx/Circuits/EMT_DecouplingLine_Ph3.cpp @@ -0,0 +1,151 @@ +/* Copyright 2017-2021 Institute for Automation of Complex Power Systems, + * EONERC, RWTH Aachen University + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *********************************************************************************/ + +#include "dpsim/Definitions.h" +#include + +using namespace DPsim; +using namespace CPS::EMT; +using namespace CPS::EMT::Ph3; +using namespace CPS::Signal; + +void simElements() { + Real timeStep = 0.00005; + Real finalTime = 1; + String simName = "EMT_DecouplingLine_Ph3_Elements"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::ABC); + auto n2 = SimNode::make("n2", PhaseType::ABC); + auto vn1 = SimNode::make("vn1", PhaseType::ABC); + + // Components + auto vs = VoltageSource::make("v_1", Logger::Level::debug); + vs->setParameters( + CPS::Math::singlePhaseVariableToThreePhase(CPS::Math::polar(100000, 0)), + 50); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto res = Resistor::make("R_line", Logger::Level::debug); + res->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance)); + auto ind = Inductor::make("L_line", Logger::Level::debug); + ind->setParameters(CPS::Math::singlePhaseParameterToThreePhase(inductance)); + auto cap1 = Capacitor::make("Cp_1", Logger::Level::debug); + cap1->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(capacitance / 2.)); + auto cap2 = Capacitor::make("Cp_2", Logger::Level::debug); + cap2->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(capacitance / 2.)); + auto con1 = Resistor::make("Gp_1", Logger::Level::debug); + con1->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(2. / conductance)); + auto con2 = Resistor::make("Gp_2", Logger::Level::debug); + con2->setParameters( + CPS::Math::singlePhaseParameterToThreePhase(2. / conductance)); + + auto load = Resistor::make("R_load", Logger::Level::debug); + load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); + + // Topology + vs->connect({SimNode::GND, n1}); + res->connect({n1, vn1}); + ind->connect({vn1, n2}); + cap1->connect({n1, SimNode::GND}); + cap2->connect({n2, SimNode::GND}); + con1->connect({n1, SimNode::GND}); + con2->connect({n2, SimNode::GND}); + load->connect({n2, SimNode::GND}); + + auto sys = SystemTopology( + 50, SystemNodeList{n1, n2, vn1}, + SystemComponentList{vs, res, ind, cap1, cap2, con1, con2, load}); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", ind->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::debug); + sim.setSystem(sys); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simDecouplingLine_Ph3() { + Real timeStep = 0.00005; + Real finalTime = 0.1; + String simName = "EMT_DecouplingLine_Ph3_Component"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::ABC); + auto n2 = SimNode::make("n2", PhaseType::ABC); + + // Components + auto vs = VoltageSource::make("v_1", Logger::Level::debug); + Real VsRefRMS = 100000 * PEAK1PH_TO_RMS3PH; + MatrixComp VsRefPh3 = + CPS::Math::singlePhaseVariableToThreePhase(Complex(VsRefRMS, 0)); + vs->setParameters(VsRefPh3, 50); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + + auto dline = DecouplingLineEMT_Ph3::make("dline", Logger::Level::debug); + dline->setParameters( + n1, n2, CPS::Math::singlePhaseParameterToThreePhase(resistance), + CPS::Math::singlePhaseParameterToThreePhase(inductance), + CPS::Math::singlePhaseParameterToThreePhase(capacitance)); + + auto load = Resistor::make("R_load", Logger::Level::debug); + load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); + + // Topology + vs->connect({SimNode::GND, n1}); + load->connect({n2, SimNode::GND}); + + auto sys = SystemTopology(50, SystemNodeList{n1, n2}, + SystemComponentList{vs, dline, load}); + sys.addComponents(dline->getLineComponents()); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("1_i1", vs->attribute("i_intf")); + logger->logAttribute("2_i_src1", dline->attribute("i_src1")); + logger->logAttribute("3_i_src2", dline->attribute("i_src2")); + logger->logAttribute("4_i2", load->attribute("i_intf")); + logger->logAttribute("5_v1", n1->attribute("v")); + logger->logAttribute("6_v2", n2->attribute("v")); + + Simulation sim(simName, Logger::Level::debug); + sim.setSystem(sys); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +int main(int argc, char *argv[]) { + simElements(); + simDecouplingLine_Ph3(); +} diff --git a/dpsim/examples/cxx/Circuits/EMT_Ph1_General2TerminalSSN.cpp b/dpsim/examples/cxx/Circuits/EMT_Ph1_General2TerminalSSN.cpp new file mode 100644 index 0000000000..893ba4bb3a --- /dev/null +++ b/dpsim/examples/cxx/Circuits/EMT_Ph1_General2TerminalSSN.cpp @@ -0,0 +1,373 @@ +// SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University +// SPDX-License-Identifier: MPL-2.0 + +#include + +using namespace DPsim; +using namespace CPS::EMT; + +void EMT_Ph1_C1R1Vs_RC() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_C1R1Vs_RC"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + auto n2 = SimNode::make("n2", PhaseType::Single); + + // Components + + auto c = Ph1::Capacitor::make("c_rc"); + c->setParameters(0.01); + + auto r = Ph1::Resistor::make("r_rc"); + r->setParameters(10.0); + + auto vs = Ph1::VoltageSource::make("vs_rc"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + c->connect(SimNode::List{n1, n2}); + r->connect(SimNode::List{n2, SimNode::GND}); + + // Define system topology + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, c, r}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_c_rc", c->attribute("v_intf")); + logger->logAttribute("i_c_rc", c->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +void EMT_Ph1_C1R1Vs_generalizedSSN() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_C1R1Vs_generalizedSSN"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + auto n2 = SimNode::make("n2", PhaseType::Single); + + // Components + + auto c = Ph1::SSNTypeI2T::make("c_genSSN"); + //du_c/dt = i_c/c , y = u_c --> u = i_c, x = u_c, A = 0, B = 1/c, C = 1, D = 0 + double c_param = 0.01; + Matrix A = Matrix::Zero(1, 1); + Matrix B = Matrix::Zero(1, 1); + B(0, 0) = (1 / c_param); + Matrix C = Matrix::Zero(1, 1); + C(0, 0) = 1; + Matrix D = Matrix::Zero(1, 1); + c->setParameters(A, B, C, D); + + auto r = Ph1::Resistor::make("r_genSSN"); + r->setParameters(10.0); + + auto vs = Ph1::VoltageSource::make("vs_genSSN"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + c->connect(SimNode::List{n1, n2}); + r->connect(SimNode::List{n2, SimNode::GND}); + + // Define system topology + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, c, r}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_c_genSSN", c->attribute("v_intf")); + logger->logAttribute("i_c_genSSN", c->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +void EMT_Ph1_L1R1Vs_RC() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_L1R1Vs_RC"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + auto n2 = SimNode::make("n2", PhaseType::Single); + + // Components + + auto l = Ph1::Inductor::make("l_rc"); + l->setParameters(0.01); + + auto r = Ph1::Resistor::make("r_rc"); + r->setParameters(10.0); + + auto vs = Ph1::VoltageSource::make("vs_rc"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + l->connect(SimNode::List{n1, n2}); + r->connect(SimNode::List{n2, SimNode::GND}); + + // Define system topology + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, l, r}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_l_rc", l->attribute("v_intf")); + logger->logAttribute("i_l_rc", l->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +void EMT_Ph1_L1R1Vs_generalizedSSN() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_L1R1Vs_generalizedSSN"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + auto n2 = SimNode::make("n2", PhaseType::Single); + + // Components + + auto l = Ph1::SSNTypeV2T::make("l_genSSN"); + //di_L/dt = v_L/L , y = i_L --> u = v_L, x = i_L, A = 0, B = 1/L, C = 1, D = 0 + double l_param = 0.01; + Matrix A = Matrix::Zero(1, 1); + Matrix B = Matrix::Zero(1, 1); + B(0, 0) = (1 / l_param); + Matrix C = Matrix::Zero(1, 1); + C(0, 0) = 1; + Matrix D = Matrix::Zero(1, 1); + l->setParameters(A, B, C, D); + + auto r = Ph1::Resistor::make("R1"); + r->setParameters(10.0); + + auto vs = Ph1::VoltageSource::make("vs"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + l->connect(SimNode::List{n1, n2}); + r->connect(SimNode::List{n2, SimNode::GND}); + + // Define system topology + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, l, r}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_l_genSSN", l->attribute("v_intf")); + logger->logAttribute("i_l_genSSN", l->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +void EMT_Ph1_RLCVs_RC() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_RLCVs_RC"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + auto n2 = SimNode::make("n2", PhaseType::Single); + auto n3 = SimNode::make("n3", PhaseType::Single); + + // Components + + auto r = Ph1::Resistor::make("r_rc"); + r->setParameters(10.0); + + auto l = Ph1::Inductor::make("l_rc"); + l->setParameters(0.01); + + auto c = Ph1::Capacitor::make("c_rc"); + c->setParameters(0.002); + + auto vs = Ph1::VoltageSource::make("vs_rc"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + r->connect(SimNode::List{n1, n2}); + l->connect(SimNode::List{n2, n3}); + c->connect(SimNode::List{n3, SimNode::GND}); + + // Define system topology + auto sys = SystemTopology(50, SystemNodeList{n1, n2, n3}, + SystemComponentList{vs, r, l, c}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_l_rlc_rc", l->attribute("v_intf")); + logger->logAttribute("i_l_rlc_rc", l->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +void EMT_Ph1_RLCVs_explicitSSN() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_RLCVs_explicitSSN"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + + // Components + + auto rlc = Ph1::SSN::Full_Serial_RLC::make("rlc"); + double r_param = 10.0; + double l_param = 0.01; + double c_param = 0.002; + + rlc->setParameters(r_param, l_param, c_param); + + auto vs = Ph1::VoltageSource::make("vs"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + rlc->connect(SimNode::List{n1, SimNode::GND}); + + // Define system topology + auto sys = + SystemTopology(50, SystemNodeList{n1}, SystemComponentList{vs, rlc}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_rlc_explSSN", rlc->attribute("v_intf")); + logger->logAttribute("i_rlc_explSSN", rlc->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +void EMT_Ph1_RLCVs_generalizedSSN() { + // Define simulation scenario + Real timeStep = 0.0001; + Real finalTime = 0.1; + String simName = "EMT_Ph1_General2TerminalSSN_RLCVs_generalizedSSN"; + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::Single); + + // Components + + auto rlc = Ph1::SSNTypeV2T::make("rlc_genSSN"); + + double r = 10.0; + double l = 0.01; + double c = 0.002; + + Matrix A = Matrix::Zero(2, 2); + A(0, 0) = 0; + A(0, 1) = 1. / c; + A(1, 0) = -1. / l; + A(1, 1) = -r / l; + Matrix B = Matrix::Zero(2, 1); + B(0, 0) = 0; + B(1, 0) = 1. / l; + Matrix C = Matrix::Zero(1, 2); + C(0, 0) = 0; + C(0, 1) = 1; + Matrix D = Matrix::Zero(1, 1); + rlc->setParameters(A, B, C, D); + + auto vs = Ph1::VoltageSource::make("vs"); + vs->setParameters((CPS::Math::polar(1.0, CPS::Math::degToRad(-90.0))), 50.0); + + // Topology + vs->connect(SimNode::List{SimNode::GND, n1}); + + rlc->connect(SimNode::List{n1, SimNode::GND}); + + // Define system topology + auto sys = + SystemTopology(50, SystemNodeList{n1}, SystemComponentList{vs, rlc}); + + // Logging + Logger::setLogDir("logs/" + simName); + auto logger = DataLogger::make(simName); + logger->logAttribute("v_rlc_genSSN", rlc->attribute("v_intf")); + logger->logAttribute("i_rlc_genSSN", rlc->attribute("i_intf")); + + Simulation sim(simName, Logger::Level::info); + sim.setSystem(sys); + sim.addLogger(logger); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.run(); +} + +int main(int argc, char *argv[]) { + EMT_Ph1_C1R1Vs_RC(); + EMT_Ph1_C1R1Vs_generalizedSSN(); + + EMT_Ph1_L1R1Vs_RC(); + EMT_Ph1_L1R1Vs_generalizedSSN(); + + EMT_Ph1_RLCVs_RC(); + EMT_Ph1_RLCVs_explicitSSN(); + EMT_Ph1_RLCVs_generalizedSSN(); +} diff --git a/dpsim/examples/cxx/Circuits/EMT_PiLine.cpp b/dpsim/examples/cxx/Circuits/EMT_PiLine.cpp index 6854b459ce..6c82b5cdcc 100644 --- a/dpsim/examples/cxx/Circuits/EMT_PiLine.cpp +++ b/dpsim/examples/cxx/Circuits/EMT_PiLine.cpp @@ -10,7 +10,6 @@ using namespace DPsim; using namespace CPS::EMT; -using namespace CPS::EMT::Ph3; void simElements() { Real timeStep = 0.00005; @@ -18,13 +17,182 @@ void simElements() { String simName = "EMT_PiLine_Elements"; Logger::setLogDir("logs/" + simName); + // Nodes + auto n1 = SimNode::make("n1"); + auto n2 = SimNode::make("n2"); + auto vn1 = SimNode::make("vn1"); + + // Components + auto vs = Ph1::VoltageSource::make("v_1"); + vs->setParameters(CPS::Math::polar(100000, 0), 50); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto res = Ph1::Resistor::make("R_line"); + res->setParameters(resistance); + auto ind = Ph1::Inductor::make("L_line"); + ind->setParameters(inductance); + auto cap1 = Ph1::Capacitor::make("Cp_1"); + cap1->setParameters(capacitance / 2.); + auto cap2 = Ph1::Capacitor::make("Cp_2"); + cap2->setParameters(capacitance / 2.); + auto con1 = Ph1::Resistor::make("Gp_1"); + con1->setParameters(2. / conductance); + auto con2 = Ph1::Resistor::make("Gp_2"); + con2->setParameters(2. / conductance); + + auto load = Ph1::Resistor::make("R_load"); + load->setParameters(10000); + + // Topology + vs->connect({SimNode::GND, n1}); + res->connect({n1, vn1}); + ind->connect({vn1, n2}); + cap1->connect({n1, SimNode::GND}); + cap2->connect({n2, SimNode::GND}); + con1->connect({n1, SimNode::GND}); + con2->connect({n2, SimNode::GND}); + load->connect({n2, SimNode::GND}); + + auto sys = SystemTopology( + 50, SystemNodeList{n1, n2, vn1}, + SystemComponentList{vs, res, ind, cap1, cap2, con1, con2, load}); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", ind->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simPiLine() { + Real timeStep = 0.00005; + Real finalTime = 1; + String simName = "EMT_PiLine_Component"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1"); + auto n2 = SimNode::make("n2"); + + // Components + auto vs = Ph1::VoltageSource::make("v_1"); + vs->setParameters(CPS::Math::polar(100000, 0), 50); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto line = Ph1::PiLine::make("Line"); + line->setParameters(resistance, inductance, capacitance, conductance); + + auto load = Ph1::Resistor::make("R_load"); + load->setParameters(10000); + + // Topology + vs->connect({SimNode::GND, n1}); + line->connect({n1, n2}); + load->connect({n2, SimNode::GND}); + + auto sys = SystemTopology(50, SystemNodeList{n1, n2}, + SystemComponentList{vs, line, load}); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", line->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setDomain(Domain::EMT); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simPiLineDiakoptics() { + Real timeStep = 0.00005; + Real finalTime = 1; + String simName = "EMT_PiLine_Diakoptics"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1"); + auto n2 = SimNode::make("n2"); + + // Components + auto vs = Ph1::VoltageSource::make("v_1"); + vs->setParameters(CPS::Math::polar(100000, 0), 50); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto line = Ph1::PiLine::make("Line"); + line->setParameters(resistance, inductance, capacitance, conductance); + + auto load = Ph1::Resistor::make("R_load"); + load->setParameters(10000); + + // Topology + vs->connect({SimNode::GND, n1}); + line->connect({n1, n2}); + load->connect({n2, SimNode::GND}); + + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, load}); + sys.addTearComponent(line); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", line->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setDomain(Domain::EMT); + sim.setTearingComponents(sys.mTearComponents); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + +void simElements3ph() { + Real timeStep = 0.00005; + Real finalTime = 1; + String simName = "EMT_PiLine_Elements_3ph"; + Logger::setLogDir("logs/" + simName); + // Nodes auto n1 = SimNode::make("n1", PhaseType::ABC); auto n2 = SimNode::make("n2", PhaseType::ABC); auto vn1 = SimNode::make("vn1", PhaseType::ABC); // Components - auto vs = VoltageSource::make("v_1", Logger::Level::debug); + auto vs = Ph3::VoltageSource::make("v_1", Logger::Level::debug); vs->setParameters( CPS::Math::singlePhaseVariableToThreePhase(CPS::Math::polar(100000, 0)), 50); @@ -35,24 +203,24 @@ void simElements() { Real capacitance = 1.0e-6; Real conductance = 1e-6; - auto res = Resistor::make("R_line", Logger::Level::debug); + auto res = Ph3::Resistor::make("R_line", Logger::Level::debug); res->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance)); - auto ind = Inductor::make("L_line", Logger::Level::debug); + auto ind = Ph3::Inductor::make("L_line", Logger::Level::debug); ind->setParameters(CPS::Math::singlePhaseParameterToThreePhase(inductance)); - auto cap1 = Capacitor::make("Cp_1", Logger::Level::debug); + auto cap1 = Ph3::Capacitor::make("Cp_1", Logger::Level::debug); cap1->setParameters( CPS::Math::singlePhaseParameterToThreePhase(capacitance / 2.)); - auto cap2 = Capacitor::make("Cp_2", Logger::Level::debug); + auto cap2 = Ph3::Capacitor::make("Cp_2", Logger::Level::debug); cap2->setParameters( CPS::Math::singlePhaseParameterToThreePhase(capacitance / 2.)); - auto con1 = Resistor::make("Gp_1", Logger::Level::debug); + auto con1 = Ph3::Resistor::make("Gp_1", Logger::Level::debug); con1->setParameters( CPS::Math::singlePhaseParameterToThreePhase(2. / conductance)); - auto con2 = Resistor::make("Gp_2", Logger::Level::debug); + auto con2 = Ph3::Resistor::make("Gp_2", Logger::Level::debug); con2->setParameters( CPS::Math::singlePhaseParameterToThreePhase(2. / conductance)); - auto load = Resistor::make("R_load", Logger::Level::debug); + auto load = Ph3::Resistor::make("R_load", Logger::Level::debug); load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); // Topology @@ -87,10 +255,10 @@ void simElements() { sim.run(); } -void simPiLine() { +void simPiLine3ph() { Real timeStep = 0.00005; Real finalTime = 1; - String simName = "EMT_PiLine_Component"; + String simName = "EMT_PiLine_Component_3ph"; Logger::setLogDir("logs/" + simName); // Nodes @@ -99,7 +267,7 @@ void simPiLine() { auto vn1 = SimNode::make("vn1", PhaseType::ABC); // Components - auto vs = VoltageSource::make("v_1", Logger::Level::debug); + auto vs = Ph3::VoltageSource::make("v_1", Logger::Level::debug); vs->setParameters( CPS::Math::singlePhaseVariableToThreePhase(CPS::Math::polar(100000, 0)), 50); @@ -110,13 +278,13 @@ void simPiLine() { Real capacitance = 1.0e-6; Real conductance = 1e-6; - auto line = PiLine::make("Line", Logger::Level::debug); + auto line = Ph3::PiLine::make("Line", Logger::Level::debug); line->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance), CPS::Math::singlePhaseParameterToThreePhase(inductance), CPS::Math::singlePhaseParameterToThreePhase(capacitance), CPS::Math::singlePhaseParameterToThreePhase(conductance)); - auto load = Resistor::make("R_load", Logger::Level::debug); + auto load = Ph3::Resistor::make("R_load", Logger::Level::debug); load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); // Topology @@ -143,7 +311,69 @@ void simPiLine() { sim.run(); } +void simPiLineDiakoptics3ph() { + Real timeStep = 0.00005; + Real finalTime = 0.1; + String simName = "EMT_PiLine_Diakoptics_3ph"; + Logger::setLogDir("logs/" + simName); + + // Nodes + auto n1 = SimNode::make("n1", PhaseType::ABC); + auto n2 = SimNode::make("n2", PhaseType::ABC); + + // Components + auto vs = Ph3::VoltageSource::make("v_1", Logger::Level::debug); + vs->setParameters( + CPS::Math::singlePhaseVariableToThreePhase(CPS::Math::polar(100000, 0)), + 50); + + // Parametrization of components + Real resistance = 5; + Real inductance = 0.16; + Real capacitance = 1.0e-6; + Real conductance = 1e-6; + + auto line = Ph3::PiLine::make("Line", Logger::Level::debug); + line->setParameters(CPS::Math::singlePhaseParameterToThreePhase(resistance), + CPS::Math::singlePhaseParameterToThreePhase(inductance), + CPS::Math::singlePhaseParameterToThreePhase(capacitance), + CPS::Math::singlePhaseParameterToThreePhase(conductance)); + + auto load = Ph3::Resistor::make("R_load", Logger::Level::debug); + load->setParameters(CPS::Math::singlePhaseParameterToThreePhase(10000)); + + // Topology + vs->connect({SimNode::GND, n1}); + line->connect({n1, n2}); + load->connect({n2, SimNode::GND}); + + auto sys = + SystemTopology(50, SystemNodeList{n1, n2}, SystemComponentList{vs, load}); + sys.addTearComponent(line); + + // Logging + auto logger = DataLogger::make(simName); + logger->logAttribute("v1", n1->attribute("v")); + logger->logAttribute("v2", n2->attribute("v")); + logger->logAttribute("iline", line->attribute("i_intf")); + + Simulation sim(simName); + sim.setSystem(sys); + sim.setDomain(Domain::EMT); + sim.setTearingComponents(sys.mTearComponents); + sim.setTimeStep(timeStep); + sim.setFinalTime(finalTime); + sim.addLogger(logger); + + sim.run(); +} + int main(int argc, char *argv[]) { simElements(); simPiLine(); + simPiLineDiakoptics(); + + simElements3ph(); + simPiLine3ph(); + simPiLineDiakoptics3ph(); } diff --git a/dpsim/examples/cxx/Components/DP_SynGenDq7odODEint_ThreePhFault.cpp b/dpsim/examples/cxx/Components/DP_SynGenDq7odODEint_ThreePhFault.cpp index a09031cd5d..8fbf3457ed 100644 --- a/dpsim/examples/cxx/Components/DP_SynGenDq7odODEint_ThreePhFault.cpp +++ b/dpsim/examples/cxx/Components/DP_SynGenDq7odODEint_ThreePhFault.cpp @@ -13,13 +13,13 @@ using namespace DPsim; using namespace CPS::DP; using namespace CPS::DP::Ph3; -/*###### For execution at least one command line argument is required: ########### - First argument: binary flag (0 or 1), - 0: The Generator Equations are solved without using the ODE-Simulation Class - 1: The Generator Equations are solved using the ODE-Simulation Class - - This is a general Test of the ODEintSolver Class. TODO: Add ODEint Solver option to Sim_ODE interface - */ +/* For execution at least one command line argument is required: + * First argument: binary flag (0 or 1), + * 0: The Generator Equations are solved without using the ODE-Simulation Class + * 1: The Generator Equations are solved using the ODE-Simulation Class + * + * This is a general Test of the ODEintSolver Class. TODO: Add ODEint Solver option to Sim_ODE interface + */ int main(int argc, char *argv[]) { // Define simulation parameters diff --git a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_BalancedResLoad.cpp b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_BalancedResLoad.cpp index 77693461db..cc599b977a 100644 --- a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_BalancedResLoad.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_BalancedResLoad.cpp @@ -77,9 +77,9 @@ int main(int argc, char *argv[]) { // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.run(); diff --git a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ExciterAndTurbine.cpp b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ExciterAndTurbine.cpp index 717e9ca320..2d83691f8c 100644 --- a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ExciterAndTurbine.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ExciterAndTurbine.cpp @@ -128,9 +128,9 @@ int main(int argc, char *argv[]) { // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(1, 1); diff --git a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_SimpThreePhaseFault.cpp b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_SimpThreePhaseFault.cpp index f841ff9945..7c3451c503 100644 --- a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_SimpThreePhaseFault.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_SimpThreePhaseFault.cpp @@ -21,13 +21,13 @@ int main(int argc, char *argv[]) { Real H = 3.7; #if 0 - Real Ka = 20; - Real Ta = 0.2; - Real Ke = 1; - Real Te = 0.314; - Real Kf = 0.063; - Real Tf = 0.35; - Real Tr = 0.02; + Real Ka = 20; + Real Ta = 0.2; + Real Ke = 1; + Real Te = 0.314; + Real Kf = 0.063; + Real Tf = 0.35; + Real Tr = 0.02; #endif Real Rs = 0.003; @@ -107,9 +107,9 @@ int main(int argc, char *argv[]) { // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(0.1, 1); diff --git a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_Simplified_ThreePhaseFault.cpp b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_Simplified_ThreePhaseFault.cpp index ec789fcb1c..b8912301b0 100644 --- a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_Simplified_ThreePhaseFault.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_Simplified_ThreePhaseFault.cpp @@ -99,9 +99,9 @@ int main(int argc, char *argv[]) { // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(0.1, 1); diff --git a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ThreePhaseFault.cpp b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ThreePhaseFault.cpp index 5413348b1c..f4cd6fe687 100644 --- a/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ThreePhaseFault.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/DP_SynchronGenerator_ThreePhaseFault.cpp @@ -95,9 +95,9 @@ int main(int argc, char *argv[]) { // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(0.1, 1); diff --git a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ExciterAndTurbine.cpp b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ExciterAndTurbine.cpp index 27486d691b..d5e7b21195 100644 --- a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ExciterAndTurbine.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ExciterAndTurbine.cpp @@ -126,9 +126,9 @@ int main(int argc, char *argv[]) { #endif // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(1, 1); diff --git a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_PhaseToPhaseFault.cpp b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_PhaseToPhaseFault.cpp index 26b294f1ec..f1135ab8da 100644 --- a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_PhaseToPhaseFault.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_PhaseToPhaseFault.cpp @@ -85,9 +85,9 @@ int main(int argc, char *argv[]) { // Calculate initial values for circuit at generator connection point #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(0.1, 1); diff --git a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_Simplified_ThreePhaseFault.cpp b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_Simplified_ThreePhaseFault.cpp index 87e94180ab..0e981ad3d4 100644 --- a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_Simplified_ThreePhaseFault.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_Simplified_ThreePhaseFault.cpp @@ -12,94 +12,92 @@ using namespace DPsim; using namespace CPS::EMT::Ph3; int main(int argc, char *argv[]) { - /* simplified VBR model does not exist at the moment - - // Define machine parameters in per unit - Real nomPower = 555e6; - Real nomPhPhVoltRMS = 24e3; - Real nomFreq = 60; - Real nomFieldCurr = 1300; - Int poleNum = 2; - Real H = 3.7; - - Real Rs = 0.003; - Real Ll = 0.15; - Real Lmd = 1.6599; - Real Lmd0 = 1.6599; - Real Lmq = 1.61; - Real Lmq0 = 1.61; - Real Rfd = 0.0006; - Real Llfd = 0.1648; - Real Rkd = 0.0284; - Real Llkd = 0.1713; - Real Rkq1 = 0.0062; - Real Llkq1 = 0.7252; - Real Rkq2 = 0.0237; - Real Llkq2 = 0.125; - //Real Rkq2 = 0; - //Real Llkq2 = 0; - - Real Ld_s = 0.23; - Real Lq_s = 0.25; - - // Set up simulation - Real om = 2.0*M_PI*60.0; - Real tf = 3; - Real dt = 0.00001; - Int downSampling = 1; - - Real Ra = (Ld_s + Lq_s) / dt; - - // Declare circuit components - Component::Ptr gen = SynchronGeneratorVBRSmpl::make("EMT_VBRSimplified_", 0, 1, 2, - nomPower, nomPhPhVoltRMS, nomFreq, poleNum, nomFieldCurr, - Rs, Ll, Lmd, Lmd0, Lmq, Lmq0, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2, Llkq2, H, Logger::Level::info); - Real loadRes = 24e3*24e3/300e6; - Component::Ptr r1 = Resistor::make("r1", 0, DEPRECATEDGND, loadRes); - Component::Ptr r2 = Resistor::make("r2", 1, DEPRECATEDGND, loadRes); - Component::Ptr r3 = Resistor::make("r3", 2, DEPRECATEDGND, loadRes); - - SystemTopology system(60); - system.mComponents = { gen, r1, r2, r3 }; - - // Declare circuit components for resistance change - //Real breakerRes = 0.001; - Real breakerRes = 19.2 + 0.001; - Component::Ptr rBreaker1 = Resistor::make("rbreak1", 0, DEPRECATEDGND, breakerRes); - Component::Ptr rBreaker2 = Resistor::make("rbreak2", 1, DEPRECATEDGND, breakerRes); - Component::Ptr rBreaker3 = Resistor::make("rbreak3", 2, DEPRECATEDGND, breakerRes); - - - SystemTopology systemBreakerOn(60); - systemBreakerOn.mComponents = { gen, rBreaker1, rBreaker2, rBreaker3, r1, r2, r3 }; - - String mSimulationName = "EMT_SynchronGenerator_VBRSimplified_" + std::to_string(dt); - Simulation sim(mSimulationName, system, dt, tf, Domain::EMT); - sim.setLogDownsamplingRate(downSampling); - sim.addSystemTopology(systemBreakerOn); - - // Initialize generator - Real initActivePower = 300e6; - Real initReactivePower = 0; - Real initTerminalVolt = 24000 / sqrt(3) * sqrt(2); - Real initVoltAngle = -DPS_PI / 2; - Real mechPower = 300e6; - auto genPtr = std::dynamic_pointer_cast(gen); - genPtr->initialize(om, dt, initActivePower, initReactivePower, initTerminalVolt, initVoltAngle, mechPower); - - // Calculate initial values for circuit at generator connection point +// Simplified VBR model does not exist at the moment #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + // Define machine parameters in per unit + Real nomPower = 555e6; + Real nomPhPhVoltRMS = 24e3; + Real nomFreq = 60; + Real nomFieldCurr = 1300; + Int poleNum = 2; + Real H = 3.7; + + Real Rs = 0.003; + Real Ll = 0.15; + Real Lmd = 1.6599; + Real Lmd0 = 1.6599; + Real Lmq = 1.61; + Real Lmq0 = 1.61; + Real Rfd = 0.0006; + Real Llfd = 0.1648; + Real Rkd = 0.0284; + Real Llkd = 0.1713; + Real Rkq1 = 0.0062; + Real Llkq1 = 0.7252; + Real Rkq2 = 0.0237; + Real Llkq2 = 0.125; + //Real Rkq2 = 0; + //Real Llkq2 = 0; + + Real Ld_s = 0.23; + Real Lq_s = 0.25; + + // Set up simulation + Real om = 2.0*M_PI*60.0; + Real tf = 3; + Real dt = 0.00001; + Int downSampling = 1; + + Real Ra = (Ld_s + Lq_s) / dt; + + // Declare circuit components + Component::Ptr gen = SynchronGeneratorVBRSmpl::make("EMT_VBRSimplified_", 0, 1, 2, + nomPower, nomPhPhVoltRMS, nomFreq, poleNum, nomFieldCurr, + Rs, Ll, Lmd, Lmd0, Lmq, Lmq0, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2, Llkq2, H, Logger::Level::info); + Real loadRes = 24e3*24e3/300e6; + Component::Ptr r1 = Resistor::make("r1", 0, DEPRECATEDGND, loadRes); + Component::Ptr r2 = Resistor::make("r2", 1, DEPRECATEDGND, loadRes); + Component::Ptr r3 = Resistor::make("r3", 2, DEPRECATEDGND, loadRes); + + SystemTopology system(60); + system.mComponents = { gen, r1, r2, r3 }; + + // Declare circuit components for resistance change + Real breakerRes = 19.2 + 0.001; + Component::Ptr rBreaker1 = Resistor::make("rbreak1", 0, DEPRECATEDGND, breakerRes); + Component::Ptr rBreaker2 = Resistor::make("rbreak2", 1, DEPRECATEDGND, breakerRes); + Component::Ptr rBreaker3 = Resistor::make("rbreak3", 2, DEPRECATEDGND, breakerRes); + + + SystemTopology systemBreakerOn(60); + systemBreakerOn.mComponents = { gen, rBreaker1, rBreaker2, rBreaker3, r1, r2, r3 }; + + String mSimulationName = "EMT_SynchronGenerator_VBRSimplified_" + std::to_string(dt); + Simulation sim(mSimulationName, system, dt, tf, Domain::EMT); + sim.setLogDownsamplingRate(downSampling); + sim.addSystemTopology(systemBreakerOn); + + // Initialize generator + Real initActivePower = 300e6; + Real initReactivePower = 0; + Real initTerminalVolt = 24000 / sqrt(3) * sqrt(2); + Real initVoltAngle = -DPS_PI / 2; + Real mechPower = 300e6; + auto genPtr = std::dynamic_pointer_cast(gen); + genPtr->initialize(om, dt, initActivePower, initReactivePower, initTerminalVolt, initVoltAngle, mechPower); + + // Calculate initial values for circuit at generator connection point +#if 0 + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif - sim.setSwitchTime(0.1, 1); - sim.setSwitchTime(0.2, 0); - - sim.run(); + sim.setSwitchTime(0.1, 1); + sim.setSwitchTime(0.2, 0); - */ + sim.run(); +#endif return 0; } diff --git a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ThreePhaseFault.cpp b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ThreePhaseFault.cpp index 99c5911c17..599f18c551 100644 --- a/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ThreePhaseFault.cpp +++ b/dpsim/examples/cxx/Components/Deprecated/EMT_SynchronGenerator_ThreePhaseFault.cpp @@ -12,7 +12,7 @@ using namespace DPsim; using namespace CPS::EMT::Ph3; int main(int argc, char *argv[]) { - // Define machine parameters in per unit + // Define machine parameters in per unit. Real nomPower = 555e6; Real nomPhPhVoltRMS = 24e3; Real nomFreq = 60; @@ -34,13 +34,14 @@ int main(int argc, char *argv[]) { Real Llkq1 = 0.7252; Real Rkq2 = 0.0237; Real Llkq2 = 0.125; - //Real Rkq2 = 0; - //Real Llkq2 = 0; - +#if 0 + Real Rkq2 = 0; + Real Llkq2 = 0; +#endif Real Ld_s = 0.23; Real Lq_s = 0.25; - // Set up simulation + // Set up simulation. Real tf, dt; Real om = 2.0 * M_PI * 60.0; tf = 0.3; @@ -49,7 +50,7 @@ int main(int argc, char *argv[]) { Real Ra = (Ld_s + Lq_s) / dt; - // Declare circuit components + // Declare circuit components. Component::Ptr gen = SynchronGeneratorDQ::make( "gen", 0, 1, 2, nomPower, nomPhPhVoltRMS, nomFreq, poleNum, nomFieldCurr, Rs, Ll, Lmd, Lmd0, Lmq, Lmq0, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2, @@ -62,7 +63,7 @@ int main(int argc, char *argv[]) { SystemTopology system(60); system.mComponents = {gen, r1, r2, r3}; - // Declare circuit components for resistance change + // Declare circuit components for resistance change. Real breakerRes = 0.001; Component::Ptr rBreaker1 = Resistor::make("rbreak1", 0, DEPRECATEDGND, breakerRes); @@ -84,7 +85,7 @@ int main(int argc, char *argv[]) { sim.setLogDownsamplingRate(downSampling); sim.addSystemTopology(systemBreakerOn); - // Initialize generator + // Initialize generator. Real initActivePower = 300e6; Real initReactivePower = 0; Real initTerminalVolt = 24000 / sqrt(3) * sqrt(2); @@ -94,11 +95,11 @@ int main(int argc, char *argv[]) { genPtr->initialize(om, dt, initActivePower, initReactivePower, initTerminalVolt, initVoltAngle, mechPower); - // Calculate initial values for circuit at generator connection point + // Calculate initial values for circuit at generator connection point. #if 0 - Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); - Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); - Real initPowerFactor = acos(initActivePower / initApparentPower); + Real initApparentPower = sqrt(pow(initActivePower, 2) + pow(initReactivePower, 2)); + Real initTerminalCurr = initApparentPower / (3 * initTerminalVolt)* sqrt(2); + Real initPowerFactor = acos(initActivePower / initApparentPower); #endif sim.setSwitchTime(0.1, 1); diff --git a/dpsim/examples/cxx/GeneratorFactory.h b/dpsim/examples/cxx/GeneratorFactory.h index dfd1c67c43..c98ef7bb2a 100644 --- a/dpsim/examples/cxx/GeneratorFactory.h +++ b/dpsim/examples/cxx/GeneratorFactory.h @@ -59,4 +59,4 @@ createGenEMT(const String &SGModel, const String &name, return genEMT; } -} // namespace GeneratorFactory \ No newline at end of file +} // namespace GeneratorFactory diff --git a/dpsim/examples/cxx/cim_graphviz/CMakeLists.txt b/dpsim/examples/cxx/cim_graphviz/CMakeLists.txt index 4a81584785..940c0c5c1e 100644 --- a/dpsim/examples/cxx/cim_graphviz/CMakeLists.txt +++ b/dpsim/examples/cxx/cim_graphviz/CMakeLists.txt @@ -1,4 +1,4 @@ if(WITH_GRAPHVIZ AND WITH_CIM) add_executable(cimviz cimviz.cpp) - target_link_libraries(cimviz PUBLIC dpsim-models libcimpp ${GRAPHVIZ_LIBRARIES}) + target_link_libraries(cimviz PUBLIC dpsim-models CIMPP::cimpp ${GRAPHVIZ_LIBRARIES}) endif() diff --git a/dpsim/examples/cxx/cim_graphviz/cimviz.cpp b/dpsim/examples/cxx/cim_graphviz/cimviz.cpp index e1b1487d94..1861b430e7 100644 --- a/dpsim/examples/cxx/cim_graphviz/cimviz.cpp +++ b/dpsim/examples/cxx/cim_graphviz/cimviz.cpp @@ -21,12 +21,12 @@ static graph_t *G; #ifndef _WIN32 static void intr(int s) { - /* if interrupted we try to produce a partial rendering before exiting */ + // If interrupted we try to produce a partial rendering before exiting. if (G) gvRenderJobs(gvc, G); /* Note that we don't call gvFinalize() so that we don't start event-driven - * devices like -Tgtk or -Txlib */ + * devices like -Tgtk or -Txlib */ exit(gvFreeContext(gvc)); } #endif @@ -37,14 +37,14 @@ struct GVC_s { char *config_path; bool config_found; - /* gvParseArgs */ + // gvParseArgs char **input_filenames; }; int main(int argc, char *argv[]) { int ret, i; - argv[0] = (char *)"neato"; /* Default layout engine */ + argv[0] = (char *)"neato"; // Default layout engine. gvc = gvContext(); gvParseArgs(gvc, argc, argv); @@ -64,13 +64,13 @@ int main(int argc, char *argv[]) { if (i == 0) return 0; - /* The remaining code is identical to GraphVizs dot.c code */ + // The remaining code is identical to GraphVizs dot.c code. SystemTopology sys = reader.loadCIM(50, filenames); Graph::Graph graph = sys.topologyGraph(); G = graph.mGraph; - ret = gvLayoutJobs(gvc, G); /* take layout engine from command line */ + ret = gvLayoutJobs(gvc, G); // Take layout engine from command line. if (ret) goto out; diff --git a/dpsim/examples/cxx/test_RealTime.yml b/dpsim/examples/cxx/test_RealTime.yml index 7466ecdad4..d1f5a90c13 100644 --- a/dpsim/examples/cxx/test_RealTime.yml +++ b/dpsim/examples/cxx/test_RealTime.yml @@ -1,2 +1,2 @@ RT_DP_ResVS_RL1: - cmd: build/dpsim/examples/cxx/RT_DP_VS_RL2 \ No newline at end of file + cmd: build/dpsim/examples/cxx/RT_DP_VS_RL2 diff --git a/dpsim/examples/cxx/test_Shmem.yml b/dpsim/examples/cxx/test_Shmem.yml index 552ca0ad69..67f2a53bd8 100644 --- a/dpsim/examples/cxx/test_Shmem.yml +++ b/dpsim/examples/cxx/test_Shmem.yml @@ -7,4 +7,4 @@ Shmem_WSCC_9bus_Ctrl: ShmemDistributedDirect: skip: true shell: True - cmd: configs/start_ShmemDistributedDirect.sh \ No newline at end of file + cmd: configs/start_ShmemDistributedDirect.sh diff --git a/dpsim/include/DPsim.h b/dpsim/include/DPsim.h index 1ddb1d424e..7cdf47bb0c 100644 --- a/dpsim/include/DPsim.h +++ b/dpsim/include/DPsim.h @@ -11,6 +11,7 @@ #include #ifndef _MSC_VER +#include #include #endif @@ -21,6 +22,8 @@ #include #endif +#include + #ifdef WITH_OPENMP #include #endif @@ -36,4 +39,5 @@ using PhaseType = CPS::PhaseType; #ifdef WITH_CIM using CIMReader = CPS::CIM::Reader; #endif +using CSVReader = CPS::CSVReader; } // namespace DPsim diff --git a/dpsim/include/dpsim/Compat/getopt.h b/dpsim/include/dpsim/Compat/getopt.h index fe5a4b9415..2cf6d158b4 100644 --- a/dpsim/include/dpsim/Compat/getopt.h +++ b/dpsim/include/dpsim/Compat/getopt.h @@ -1,3 +1,4 @@ +// editorconfig-checker-disable-file #ifndef __GETOPT_H__ /** * DISCLAIMER @@ -85,13 +86,6 @@ int optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #endif -//extern int optind; /* index of first non-option in argv */ -//extern int optopt; /* single option character, as parsed */ -//extern int opterr; /* flag to enable built-in diagnostics... */ -// /* (user may set to zero, to suppress) */ -// -//extern char *optarg; /* pointer to argument of current option */ - #define PRINT_ERROR ((opterr) && (*options != ':')) #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ diff --git a/dpsim/include/dpsim/Config.h.in b/dpsim/include/dpsim/Config.h.in index 33f2e14b6a..48e34b967e 100644 --- a/dpsim/include/dpsim/Config.h.in +++ b/dpsim/include/dpsim/Config.h.in @@ -29,6 +29,7 @@ #cmakedefine WITH_MAGMA #cmakedefine WITH_KLU #cmakedefine WITH_MNASOLVERPLUGIN +#cmakedefine WITH_JSON #cmakedefine CGMES_BUILD #cmakedefine HAVE_GETOPT diff --git a/dpsim/include/dpsim/DataLogger.h b/dpsim/include/dpsim/DataLogger.h index 1654585558..7f478b7524 100644 --- a/dpsim/include/dpsim/DataLogger.h +++ b/dpsim/include/dpsim/DataLogger.h @@ -23,7 +23,8 @@ namespace DPsim { -class DataLogger : public DataLoggerInterface, public SharedFactory { +class DataLogger : public DataLoggerInterface, + public SharedFactory { protected: std::ofstream mLogFile; diff --git a/dpsim/include/dpsim/DataLoggerInterface.h b/dpsim/include/dpsim/DataLoggerInterface.h index 157cf53241..7b17e5f97c 100644 --- a/dpsim/include/dpsim/DataLoggerInterface.h +++ b/dpsim/include/dpsim/DataLoggerInterface.h @@ -28,20 +28,29 @@ class DataLoggerInterface { DataLoggerInterface() : mAttributes(){}; + virtual ~DataLoggerInterface() = default; + // Start the logger. After starting the number of columns should not be changed. virtual void start() = 0; // Stops the logger. Afterwards it should not be used anymore. virtual void stop() = 0; - virtual void logAttribute(const String &name, CPS::AttributeBase::Ptr attr, UInt rowsMax = 0, UInt colsMax = 0) { - if (auto attrReal = std::dynamic_pointer_cast>(attr.getPtr())) { + virtual void logAttribute(const String &name, CPS::AttributeBase::Ptr attr, + UInt rowsMax = 0, UInt colsMax = 0) { + if (auto attrReal = + std::dynamic_pointer_cast>(attr.getPtr())) { mAttributes[name] = attrReal; - } else if (auto attrComp = std::dynamic_pointer_cast>(attr.getPtr())) { + } else if (auto attrComp = + std::dynamic_pointer_cast>( + attr.getPtr())) { mAttributes[name + ".re"] = attrComp->deriveReal(); mAttributes[name + ".im"] = attrComp->deriveImag(); - } else if (auto attrInt = std::dynamic_pointer_cast>(attr.getPtr())) { + } else if (auto attrInt = std::dynamic_pointer_cast>( + attr.getPtr())) { mAttributes[name] = attrInt; - } else if (auto attrMatrix = std::dynamic_pointer_cast>(attr.getPtr())) { + } else if (auto attrMatrix = + std::dynamic_pointer_cast>( + attr.getPtr())) { UInt rows = static_cast((**attrMatrix).rows()); UInt cols = static_cast((**attrMatrix).cols()); if (rowsMax == 0 || rowsMax > rows) @@ -52,16 +61,21 @@ class DataLoggerInterface { mAttributes[name] = attrMatrix->deriveCoeff(0, 0); } else if (cols == 1) { for (UInt k = 0; k < rowsMax; ++k) { - mAttributes[name + "_" + std::to_string(k)] = attrMatrix->deriveCoeff(k, 0); + mAttributes[name + "_" + std::to_string(k)] = + attrMatrix->deriveCoeff(k, 0); } } else { for (UInt k = 0; k < rowsMax; ++k) { for (UInt l = 0; l < colsMax; ++l) { - mAttributes[name + "_" + std::to_string(k) + "_" + std::to_string(l)] = attrMatrix->deriveCoeff(k, l); + mAttributes[name + "_" + std::to_string(k) + "_" + + std::to_string(l)] = + attrMatrix->deriveCoeff(k, l); } } } - } else if (auto attrMatrix = std::dynamic_pointer_cast>(attr.getPtr())) { + } else if (auto attrMatrix = + std::dynamic_pointer_cast>( + attr.getPtr())) { UInt rows = static_cast((**attrMatrix).rows()); UInt cols = static_cast((**attrMatrix).cols()); if (rowsMax == 0 || rowsMax > rows) @@ -69,30 +83,41 @@ class DataLoggerInterface { if (colsMax == 0 || colsMax > cols) colsMax = cols; if (rows == 1 && cols == 1) { - mAttributes[name + ".re"] = attrMatrix->deriveCoeff(0, 0)->deriveReal(); - mAttributes[name + ".im"] = attrMatrix->deriveCoeff(0, 0)->deriveImag(); + mAttributes[name + ".re"] = + attrMatrix->deriveCoeff(0, 0)->deriveReal(); + mAttributes[name + ".im"] = + attrMatrix->deriveCoeff(0, 0)->deriveImag(); } else if (cols == 1) { for (UInt k = 0; k < rowsMax; ++k) { - mAttributes[name + "_" + std::to_string(k) + ".re"] = attrMatrix->deriveCoeff(k, 0)->deriveReal(); - mAttributes[name + "_" + std::to_string(k) + ".im"] = attrMatrix->deriveCoeff(k, 0)->deriveImag(); + mAttributes[name + "_" + std::to_string(k) + ".re"] = + attrMatrix->deriveCoeff(k, 0)->deriveReal(); + mAttributes[name + "_" + std::to_string(k) + ".im"] = + attrMatrix->deriveCoeff(k, 0)->deriveImag(); } } else { for (UInt k = 0; k < rowsMax; ++k) { for (UInt l = 0; l < colsMax; ++l) { - mAttributes[name + "_" + std::to_string(k) + "_" + std::to_string(l) + ".re"] = attrMatrix->deriveCoeff(k, l)->deriveReal(); - mAttributes[name + "_" + std::to_string(k) + "_" + std::to_string(l) + ".im"] = attrMatrix->deriveCoeff(k, l)->deriveImag(); + mAttributes[name + "_" + std::to_string(k) + "_" + + std::to_string(l) + ".re"] = + attrMatrix->deriveCoeff(k, l)->deriveReal(); + mAttributes[name + "_" + std::to_string(k) + "_" + + std::to_string(l) + ".im"] = + attrMatrix->deriveCoeff(k, l)->deriveImag(); } } } } else { - throw std::runtime_error("DataLoggerInterface: Unknown attribute type for attribute " + name); + throw std::runtime_error( + "DataLoggerInterface: Unknown attribute type for attribute " + name); } } /// DEPRECATED: Only use for compatiblity, otherwise this just adds extra overhead to the logger. Instead just call logAttribute multiple times for every coefficient using /// `attr->deriveCoeff<>(a,b)`. - void logAttribute(const std::vector &name, CPS::AttributeBase::Ptr attr) { - if (auto attrMatrix = std::dynamic_pointer_cast>(attr.getPtr())) { + void logAttribute(const std::vector &name, + CPS::AttributeBase::Ptr attr) { + if (auto attrMatrix = + std::dynamic_pointer_cast>(attr.getPtr())) { if ((**attrMatrix).rows() == 1 && (**attrMatrix).cols() == 1) { logAttribute(name[0], attrMatrix->deriveCoeff(0, 0)); } else if ((**attrMatrix).cols() == 1) { @@ -102,11 +127,14 @@ class DataLoggerInterface { } else { for (UInt k = 0; k < (**attrMatrix).rows(); ++k) { for (UInt l = 0; l < (**attrMatrix).cols(); ++l) { - logAttribute(name[k * (**attrMatrix).cols() + l], attrMatrix->deriveCoeff(k, l)); + logAttribute(name[k * (**attrMatrix).cols() + l], + attrMatrix->deriveCoeff(k, l)); } } } - } else if (auto attrMatrix = std::dynamic_pointer_cast>(attr.getPtr())) { + } else if (auto attrMatrix = + std::dynamic_pointer_cast>( + attr.getPtr())) { if ((**attrMatrix).rows() == 1 && (**attrMatrix).cols() == 1) { logAttribute(name[0], attrMatrix->deriveCoeff(0, 0)); } else if ((**attrMatrix).cols() == 1) { @@ -116,7 +144,8 @@ class DataLoggerInterface { } else { for (UInt k = 0; k < (**attrMatrix).rows(); ++k) { for (UInt l = 0; l < (**attrMatrix).cols(); ++l) { - logAttribute(name[k * (**attrMatrix).cols() + l], attrMatrix->deriveCoeff(k, l)); + logAttribute(name[k * (**attrMatrix).cols() + l], + attrMatrix->deriveCoeff(k, l)); } } } diff --git a/dpsim/include/dpsim/DiakopticsSolver.h b/dpsim/include/dpsim/DiakopticsSolver.h index 5bb020e1b8..d41159edb7 100644 --- a/dpsim/include/dpsim/DiakopticsSolver.h +++ b/dpsim/include/dpsim/DiakopticsSolver.h @@ -76,6 +76,8 @@ class DiakopticsSolver : public Solver, public CPS::AttributeList { Matrix mTearCurrents; /// Voltages across the removed network Matrix mTearVoltages; + /// PhaseType to identify matrix Sizes + CPS::PhaseType mPhaseType; void init(CPS::SystemTopology &system); diff --git a/dpsim/include/dpsim/Interface.h b/dpsim/include/dpsim/Interface.h index f4b3c473bf..2a8d6c6436 100644 --- a/dpsim/include/dpsim/Interface.h +++ b/dpsim/include/dpsim/Interface.h @@ -27,6 +27,8 @@ class Interface : public SharedFactory { mLog = CPS::Logger::get("Interface", logLevel); }; + virtual ~Interface() = default; + virtual void open() = 0; virtual void close() = 0; diff --git a/dpsim/include/dpsim/InterfaceQueued.h b/dpsim/include/dpsim/InterfaceQueued.h index 6e206d3465..e03bd9eecd 100644 --- a/dpsim/include/dpsim/InterfaceQueued.h +++ b/dpsim/include/dpsim/InterfaceQueued.h @@ -21,15 +21,18 @@ namespace DPsim { class InterfaceWorker; -class InterfaceQueued : public Interface, public SharedFactory { +class InterfaceQueued : public Interface, + public SharedFactory { public: typedef std::shared_ptr Ptr; using AttributePacket = struct AttributePacket { CPS::AttributeBase::Ptr value; - UInt attributeId; // Used to identify the attribute. Defined by the position in the `mExportAttrsDpsim` and `mImportAttrsDpsim` lists - UInt sequenceId; // Increasing ID used to discern multiple consecutive updates of a single attribute + UInt + attributeId; // Used to identify the attribute. Defined by the position in the `mExportAttrsDpsim` and `mImportAttrsDpsim` lists + UInt + sequenceId; // Increasing ID used to discern multiple consecutive updates of a single attribute unsigned char flags; // Bit 0 set: Close interface }; @@ -38,9 +41,13 @@ class InterfaceQueued : public Interface, public SharedFactory PACKET_CLOSE_INTERFACE = 1, }; - InterfaceQueued(std::shared_ptr intf, const String &name = "", UInt downsampling = 1) : Interface(name), mInterfaceWorker(intf), mDownsampling(downsampling) { - mQueueDpsimToInterface = std::make_shared>(); - mQueueInterfaceToDpsim = std::make_shared>(); + InterfaceQueued(std::shared_ptr intf, + const String &name = "", UInt downsampling = 1) + : Interface(name), mInterfaceWorker(intf), mDownsampling(downsampling) { + mQueueDpsimToInterface = std::make_shared< + moodycamel::BlockingReaderWriterQueue>(); + mQueueInterfaceToDpsim = std::make_shared< + moodycamel::BlockingReaderWriterQueue>(); }; virtual void open() override; @@ -73,37 +80,51 @@ class InterfaceQueued : public Interface, public SharedFactory std::thread mInterfaceWriterThread; std::thread mInterfaceReaderThread; - std::shared_ptr> mQueueDpsimToInterface; - std::shared_ptr> mQueueInterfaceToDpsim; + std::shared_ptr> + mQueueDpsimToInterface; + std::shared_ptr> + mQueueInterfaceToDpsim; public: class WriterThread { private: - std::shared_ptr> mQueueDpsimToInterface; + std::shared_ptr> + mQueueDpsimToInterface; std::shared_ptr mInterfaceWorker; public: - WriterThread(std::shared_ptr> queueDpsimToInterface, std::shared_ptr intf) - : mQueueDpsimToInterface(queueDpsimToInterface), mInterfaceWorker(intf){}; + WriterThread( + std::shared_ptr> + queueDpsimToInterface, + std::shared_ptr intf) + : mQueueDpsimToInterface(queueDpsimToInterface), + mInterfaceWorker(intf){}; void operator()() const; }; class ReaderThread { private: - std::shared_ptr> mQueueInterfaceToDpsim; + std::shared_ptr> + mQueueInterfaceToDpsim; std::shared_ptr mInterfaceWorker; std::atomic &mOpened; public: - ReaderThread(std::shared_ptr> queueInterfaceToDpsim, std::shared_ptr intf, std::atomic &opened) - : mQueueInterfaceToDpsim(queueInterfaceToDpsim), mInterfaceWorker(intf), mOpened(opened){}; + ReaderThread( + std::shared_ptr> + queueInterfaceToDpsim, + std::shared_ptr intf, std::atomic &opened) + : mQueueInterfaceToDpsim(queueInterfaceToDpsim), mInterfaceWorker(intf), + mOpened(opened){}; void operator()() const; }; class PreStep : public CPS::Task { public: - explicit PreStep(InterfaceQueued &intf) : Task(intf.getName() + ".Read"), mIntf(intf) { - for (const auto &[attr, _seqId, _blockOnRead, _syncOnStart] : intf.mImportAttrsDpsim) { + explicit PreStep(InterfaceQueued &intf) + : Task(intf.getName() + ".Read"), mIntf(intf) { + for (const auto &[attr, _seqId, _blockOnRead, _syncOnStart] : + intf.mImportAttrsDpsim) { mModifiedAttributes.push_back(attr); } } @@ -116,7 +137,8 @@ class InterfaceQueued : public Interface, public SharedFactory class PostStep : public CPS::Task { public: - explicit PostStep(InterfaceQueued &intf) : Task(intf.getName() + ".Write"), mIntf(intf) { + explicit PostStep(InterfaceQueued &intf) + : Task(intf.getName() + ".Write"), mIntf(intf) { for (const auto &[attr, _seqId] : intf.mExportAttrsDpsim) { mAttributeDependencies.push_back(attr); } diff --git a/dpsim/include/dpsim/InterfaceWorker.h b/dpsim/include/dpsim/InterfaceWorker.h index 75e18d7462..e46267a968 100644 --- a/dpsim/include/dpsim/InterfaceWorker.h +++ b/dpsim/include/dpsim/InterfaceWorker.h @@ -30,32 +30,32 @@ class InterfaceWorker { virtual ~InterfaceWorker() = default; /** - * Function that will be called on loop in its separate thread. - * Should be used to read values from the environment and push them into `updatedAttrs` - * `updatedAttrs` will always be empty when this function is invoked - */ + * Function that will be called on loop in its separate thread. + * Should be used to read values from the environment and push them into `updatedAttrs` + * `updatedAttrs` will always be empty when this function is invoked + */ virtual void readValuesFromEnv( std::vector &updatedAttrs) = 0; /** - * Function that will be called on loop in its separate thread. - * Should be used to read values from `updatedAttrs` and write them to the environment - * The `updatedAttrs` list will not be cleared by the caller in between function calls - * When this function is called, `updatedAttrs` will include at least one value - */ + * Function that will be called on loop in its separate thread. + * Should be used to read values from `updatedAttrs` and write them to the environment + * The `updatedAttrs` list will not be cleared by the caller in between function calls + * When this function is called, `updatedAttrs` will include at least one value. + */ virtual void writeValuesToEnv( std::vector &updatedAttrs) = 0; /** - * Open the interface and set up the connection to the environment - * This is guaranteed to be called before any calls to `readValuesFromEnv` and `writeValuesToEnv` - */ + * Open the interface and set up the connection to the environment + * This is guaranteed to be called before any calls to `readValuesFromEnv` and `writeValuesToEnv` + */ virtual void open() = 0; /** - * Close the interface and all connections to the environment - * After this has been called, no further calls to `readValuesFromEnv` or `writeValuesToEnv` will occur - */ + * Close the interface and all connections to the environment + * After this has been called, no further calls to `readValuesFromEnv` or `writeValuesToEnv` will occur + */ virtual void close() = 0; }; } // namespace DPsim diff --git a/dpsim/include/dpsim/MNASolverDynInterface.h b/dpsim/include/dpsim/MNASolverDynInterface.h index 8d311b3569..a629ffb274 100644 --- a/dpsim/include/dpsim/MNASolverDynInterface.h +++ b/dpsim/include/dpsim/MNASolverDynInterface.h @@ -25,6 +25,12 @@ struct dpsim_mna_plugin { void (*cleanup)(void); }; -extern "C" struct dpsim_mna_plugin *get_mna_plugin(const char *name); +#ifdef __cplusplus +extern "C" { +#endif +struct dpsim_mna_plugin *get_mna_plugin(const char *name); +#ifdef __cplusplus +} +#endif #endif diff --git a/dpsim/include/dpsim/MNASolverFactory.h b/dpsim/include/dpsim/MNASolverFactory.h index a349cffd0c..1dc9416e3f 100644 --- a/dpsim/include/dpsim/MNASolverFactory.h +++ b/dpsim/include/dpsim/MNASolverFactory.h @@ -52,7 +52,7 @@ class MnaSolverFactory { DirectLinearSolverImpl::DenseLU, DirectLinearSolverImpl::SparseLU, #ifdef WITH_KLU DirectLinearSolverImpl::KLU -#endif //WITH_KLU +#endif // WITH_KLU }; return ret; } @@ -77,10 +77,11 @@ class MnaSolverFactory { switch (implementation) { /* TODO: have only one "solver" object of type MnaSolverDirect and only use setDirectLinearSolverImplementation in the switch-case. - * This is not done now, since MnaSolverDirect and MnaSolver are distinct classes - and someone might add another subclass of MnaSolver - * to the project (MnaSolverIterative?). It is planned to merge MnaSolverDirect and MnaSolver anyway, so this won't happen. */ + * This is not done now, since MnaSolverDirect and MnaSolver are distinct classes - and someone might add another subclass of MnaSolver + * to the project (MnaSolverIterative?). It is planned to merge MnaSolverDirect and MnaSolver anyway, so this won't happen. + */ case DirectLinearSolverImpl::SparseLU: { - log->info("creating SparseLUAdapter solver implementation"); + SPDLOG_LOGGER_INFO(log, "creating SparseLUAdapter solver implementation"); std::shared_ptr> sparseSolver = std::make_shared>(name, domain, logLevel); sparseSolver->setDirectLinearSolverImplementation( @@ -88,7 +89,7 @@ class MnaSolverFactory { return sparseSolver; } case DirectLinearSolverImpl::DenseLU: { - log->info("creating DenseLUAdapter solver implementation"); + SPDLOG_LOGGER_INFO(log, "creating DenseLUAdapter solver implementation"); std::shared_ptr> denseSolver = std::make_shared>(name, domain, logLevel); denseSolver->setDirectLinearSolverImplementation( @@ -97,7 +98,7 @@ class MnaSolverFactory { } #ifdef WITH_KLU case DirectLinearSolverImpl::KLU: { - log->info("creating KLUAdapter solver implementation"); + SPDLOG_LOGGER_INFO(log, "creating KLUAdapter solver implementation"); std::shared_ptr> kluSolver = std::make_shared>(name, domain, logLevel); kluSolver->setDirectLinearSolverImplementation( @@ -107,7 +108,7 @@ class MnaSolverFactory { #endif #ifdef WITH_CUDA case DirectLinearSolverImpl::CUDADense: { - log->info("creating GpuDenseAdapter solver implementation"); + SPDLOG_LOGGER_INFO(log, "creating GpuDenseAdapter solver implementation"); std::shared_ptr> gpuDenseSolver = std::make_shared>(name, domain, logLevel); gpuDenseSolver->setDirectLinearSolverImplementation( @@ -116,7 +117,8 @@ class MnaSolverFactory { } #ifdef WITH_CUDA_SPARSE case DirectLinearSolverImpl::CUDASparse: { - log->info("creating GpuSparseAdapter solver implementation"); + SPDLOG_LOGGER_INFO(log, + "creating GpuSparseAdapter solver implementation"); std::shared_ptr> gpuSparseSolver = std::make_shared>(name, domain, logLevel); gpuSparseSolver->setDirectLinearSolverImplementation( @@ -126,7 +128,7 @@ class MnaSolverFactory { #endif #ifdef WITH_MAGMA case DirectLinearSolverImpl::CUDAMagma: { - log->info("creating GpuMagmaAdapter solver implementation"); + SPDLOG_LOGGER_INFO(log, "creating GpuMagmaAdapter solver implementation"); std::shared_ptr> gpuMagmaSolver = std::make_shared>(name, domain, logLevel); gpuMagmaSolver->setDirectLinearSolverImplementation( @@ -137,7 +139,7 @@ class MnaSolverFactory { #endif #ifdef WITH_MNASOLVERPLUGIN case DirectLinearSolverImpl::Plugin: - log->info("creating Plugin solver implementation"); + SPDLOG_LOGGER_INFO(log, "creating Plugin solver implementation"); return std::make_shared>(pluginName, name, domain, logLevel); #endif diff --git a/dpsim/include/dpsim/ODESolver.h b/dpsim/include/dpsim/ODESolver.h index 3d8baf2c58..81a795db6b 100644 --- a/dpsim/include/dpsim/ODESolver.h +++ b/dpsim/include/dpsim/ODESolver.h @@ -53,20 +53,14 @@ class ODESolver : public Solver { /// Scalar absolute tolerance realtype abstol = RCONST(1.0e-10); - // TODO: Variables for implicit solve? - /// Template Jacobian Matrix (implicit solver) - /* SUNMatrix A = NULL; - /// Linear solver object (implicit solver) - SUNLinearSolver LS = NULL; */ - - /// reusable error-checking flag + /// Reusable error-checking flag int mFlag{0}; // Similar to DAE-Solver CPS::ODEInterface::StSpFn mStSpFunction; CPS::ODEInterface::JacFn mJacFunction; - /// use wrappers similar to DAE_Solver + /// Use wrappers similar to DAE_Solver static int StateSpaceWrapper(realtype t, N_Vector y, N_Vector ydot, void *user_data); int StateSpace(realtype t, N_Vector y, N_Vector ydot); diff --git a/dpsim/include/dpsim/RealTimeDataLogger.h b/dpsim/include/dpsim/RealTimeDataLogger.h index ea2c8323dd..cc2402a305 100644 --- a/dpsim/include/dpsim/RealTimeDataLogger.h +++ b/dpsim/include/dpsim/RealTimeDataLogger.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -21,7 +22,8 @@ namespace DPsim { -class RealTimeDataLogger : public DataLoggerInterface, public SharedFactory { +class RealTimeDataLogger : public DataLoggerInterface, + public SharedFactory { protected: std::filesystem::path mFilename; @@ -34,7 +36,8 @@ class RealTimeDataLogger : public DataLoggerInterface, public SharedFactory Ptr; - RealTimeDataLogger(std::filesystem::path &filename, Real finalTime, Real timeStep); + RealTimeDataLogger(std::filesystem::path &filename, Real finalTime, + Real timeStep); RealTimeDataLogger(std::filesystem::path &filename, size_t rowNumber); virtual void start() override; @@ -46,7 +49,8 @@ class RealTimeDataLogger : public DataLoggerInterface, public SharedFactory #include #include -#include #ifdef WITH_GRAPHVIZ #include #endif -using json = nlohmann::json; - namespace DPsim { /// Forward declaration of CommandLineArgs from Utils class CommandLineArgs; @@ -249,7 +246,9 @@ class Simulation : public CPS::AttributeList { /// Schedule an event in the simulation void addEvent(Event::Ptr e) { mEvents.addEvent(e); } /// Add a new data logger - void addLogger(DataLoggerInterface::Ptr logger) { mLoggers.push_back(logger); } + void addLogger(DataLoggerInterface::Ptr logger) { + mLoggers.push_back(logger); + } /// Write step time measurements to log file void logStepTimes(String logName); /// Check for overruns diff --git a/dpsim/include/dpsim/Timer.h b/dpsim/include/dpsim/Timer.h index 4008d9b8ad..2f0cf09c69 100644 --- a/dpsim/include/dpsim/Timer.h +++ b/dpsim/include/dpsim/Timer.h @@ -10,6 +10,7 @@ #include +#include #include namespace DPsim { @@ -42,10 +43,15 @@ class Timer { long long mTicks; int mFlags; + /// Timer log level + CPS::Logger::Level mLogLevel; + /// Logger + CPS::Logger::Log mSLog; + public: enum Flags : int { fail_on_overrun = 1 }; - Timer(int flags = 0); + Timer(int flags = 0, CPS::Logger::Level logLevel = CPS::Logger::Level::debug); ~Timer(); diff --git a/dpsim/include/dpsim/Utils.h b/dpsim/include/dpsim/Utils.h index 4388422582..808e68d212 100644 --- a/dpsim/include/dpsim/Utils.h +++ b/dpsim/include/dpsim/Utils.h @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -28,7 +27,10 @@ #include #include +#ifdef WITH_JSON +#include using json = nlohmann::json; +#endif namespace DPsim { @@ -133,10 +135,12 @@ class CommandLineArgs { namespace Utils { +#ifdef WITH_JSON void applySimulationParametersFromJson(const json config, Simulation &sim); void applySynchronousGeneratorParametersFromJson( const json config, std::shared_ptr syngen); +#endif String encodeXml(String &data); diff --git a/dpsim/include/dpsim/pybind/Attributes.h b/dpsim/include/dpsim/pybind/Attributes.h index 542538e526..bb9eb6881b 100644 --- a/dpsim/include/dpsim/pybind/Attributes.h +++ b/dpsim/include/dpsim/pybind/Attributes.h @@ -16,4 +16,4 @@ namespace py = pybind11; using namespace pybind11::literals; -void addAttributes(py::module_ m); \ No newline at end of file +void addAttributes(py::module_ m); diff --git a/dpsim/src/CMakeLists.txt b/dpsim/src/CMakeLists.txt index e9dc0c049e..fe1227f5f7 100644 --- a/dpsim/src/CMakeLists.txt +++ b/dpsim/src/CMakeLists.txt @@ -25,8 +25,8 @@ set(DPSIM_SOURCES list(APPEND DPSIM_LIBRARIES dpsim-models - readerwriterqueue filesystem + readerwriterqueue::readerwriterqueue ) if(WITH_MNASOLVERPLUGIN) @@ -57,10 +57,8 @@ if(WITH_JSON) endif() if(WITH_KLU) - list(APPEND DPSIM_LIBRARIES klu) - list(APPEND DPSIM_SOURCES - KLUAdapter.cpp - ) + list(APPEND DPSIM_LIBRARIES SuiteSparse::KLU) + list(APPEND DPSIM_SOURCES KLUAdapter.cpp) endif() if(WITH_CUDA) @@ -77,18 +75,13 @@ if(WITH_CUDA) ) if(WITH_MAGMA) - list(APPEND DPSIM_SOURCES - GpuMagmaAdapter.cpp - ) + list(APPEND DPSIM_SOURCES GpuMagmaAdapter.cpp) list(APPEND DPSIM_LIBRARIES ${MAGMA_LIBRARIES}) list(APPEND DPSIM_LIBRARIES ${CUDA_cusparse_LIBRARY}) list(APPEND DPSIM_INCLUDE_DIRS ${MAGMA_INCLUDE_DIR}) endif() if(WITH_CUDA_SPARSE) - list(APPEND DPSIM_SOURCES - GpuSparseAdapter.cpp - ) - + list(APPEND DPSIM_SOURCES GpuSparseAdapter.cpp) list(APPEND DPSIM_LIBRARIES ${CUDA_cusparse_LIBRARY}) endif() endif() @@ -99,6 +92,17 @@ if(WITH_OPENMP) list(APPEND DPSIM_LIBRARIES ${OpenMP_CXX_FLAGS}) endif() +if(WITH_VILLAS) + list(APPEND DPSIM_LIBRARIES + ${VILLASNODE_LIBRARIES} + ${VILLASCOMMON_LIBRARIES} + pthread + ) + if(VILLASFPGA_LIBRARIES) + list(APPEND DPSIM_LIBRARIES ${VILLASFPGA_LIBRARIES}) + endif() +endif() + add_library(dpsim ${DPSIM_SOURCES}) target_link_libraries(dpsim PUBLIC ${DPSIM_LIBRARIES}) target_include_directories(dpsim PUBLIC ${DPSIM_INCLUDE_DIRS}) diff --git a/dpsim/src/DataLogger.cpp b/dpsim/src/DataLogger.cpp index c6cd23721e..28445a1509 100644 --- a/dpsim/src/DataLogger.cpp +++ b/dpsim/src/DataLogger.cpp @@ -13,9 +13,14 @@ using namespace DPsim; -DataLogger::DataLogger(Bool enabled) : DataLoggerInterface(), mLogFile(), mEnabled(enabled), mDownsampling(1) { mLogFile.setstate(std::ios_base::badbit); } +DataLogger::DataLogger(Bool enabled) + : DataLoggerInterface(), mLogFile(), mEnabled(enabled), mDownsampling(1) { + mLogFile.setstate(std::ios_base::badbit); +} -DataLogger::DataLogger(String name, Bool enabled, UInt downsampling) : DataLoggerInterface(), mName(name), mEnabled(enabled), mDownsampling(downsampling) { +DataLogger::DataLogger(String name, Bool enabled, UInt downsampling) + : DataLoggerInterface(), mName(name), mEnabled(enabled), + mDownsampling(downsampling) { if (!mEnabled) return; @@ -137,7 +142,9 @@ void DataLogger::log(Real time, Int timeStepCount) { mLogFile << '\n'; } -void DataLogger::Step::execute(Real time, Int timeStepCount) { mLogger.log(time, timeStepCount); } +void DataLogger::Step::execute(Real time, Int timeStepCount) { + mLogger.log(time, timeStepCount); +} CPS::Task::Ptr DataLogger::getTask() { return std::make_shared(*this); diff --git a/dpsim/src/DiakopticsSolver.cpp b/dpsim/src/DiakopticsSolver.cpp index 5491f9cb55..309fcf655a 100644 --- a/dpsim/src/DiakopticsSolver.cpp +++ b/dpsim/src/DiakopticsSolver.cpp @@ -46,6 +46,8 @@ template void DiakopticsSolver::init(SystemTopology &system) { std::vector subnets; mSystem = system; + if (mSystem.mNodes.size() > 0) + mPhaseType = mSystem.mNodes.at(0)->phaseType(); mSystemFrequency = system.mSystemFrequency; system.splitSubnets(subnets); @@ -234,19 +236,31 @@ template void DiakopticsSolver::createMatrices() { } template <> void DiakopticsSolver::createTearMatrices(UInt totalSize) { - mTearTopology = Matrix::Zero(totalSize, mTearComponents.size()); + int phaseMultiplier = 1; + if (mPhaseType == PhaseType::ABC) { + phaseMultiplier = 3; + } + mTearTopology = + Matrix::Zero(totalSize, mTearComponents.size() * phaseMultiplier); mTearImpedance = - CPS::SparseMatrixRow(mTearComponents.size(), mTearComponents.size()); - mTearCurrents = Matrix::Zero(mTearComponents.size(), 1); - mTearVoltages = Matrix::Zero(mTearComponents.size(), 1); + CPS::SparseMatrixRow(mTearComponents.size() * phaseMultiplier, + mTearComponents.size() * phaseMultiplier); + mTearCurrents = Matrix::Zero(mTearComponents.size() * phaseMultiplier, 1); + mTearVoltages = Matrix::Zero(mTearComponents.size() * phaseMultiplier, 1); } template <> void DiakopticsSolver::createTearMatrices(UInt totalSize) { - mTearTopology = Matrix::Zero(totalSize, 2 * mTearComponents.size()); - mTearImpedance = CPS::SparseMatrixRow(2 * mTearComponents.size(), - 2 * mTearComponents.size()); - mTearCurrents = Matrix::Zero(2 * mTearComponents.size(), 1); - mTearVoltages = Matrix::Zero(2 * mTearComponents.size(), 1); + int phaseMultiplier = 1; + if (mPhaseType == PhaseType::ABC) { + phaseMultiplier = 3; + } + mTearTopology = + Matrix::Zero(totalSize, 2 * mTearComponents.size() * phaseMultiplier); + mTearImpedance = + CPS::SparseMatrixRow(2 * mTearComponents.size() * phaseMultiplier, + 2 * mTearComponents.size() * phaseMultiplier); + mTearCurrents = Matrix::Zero(2 * mTearComponents.size() * phaseMultiplier, 1); + mTearVoltages = Matrix::Zero(2 * mTearComponents.size() * phaseMultiplier, 1); } template void DiakopticsSolver::initComponents() { @@ -325,13 +339,50 @@ template void DiakopticsSolver::initMatrices() { template <> void DiakopticsSolver::applyTearComponentStamp(UInt compIdx) { auto comp = mTearComponents[compIdx]; - mTearTopology(mNodeSubnetMap[comp->node(0)]->sysOff + - comp->node(0)->matrixNodeIndex(), - compIdx) = 1; - mTearTopology(mNodeSubnetMap[comp->node(1)]->sysOff + - comp->node(1)->matrixNodeIndex(), - compIdx) = -1; + // Use triplets to populate the sparse matrix + std::vector> triplets; + + // Node 0 contributions + if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) { + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(PhaseType::A), + compIdx * 3, 1); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(PhaseType::B), + compIdx * 3 + 1, 1); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(PhaseType::C), + compIdx * 3 + 2, 1); + } else { + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(), + compIdx, 1); + } + + // Node 1 contributions + if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) { + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(PhaseType::A), + compIdx * 3, -1); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(PhaseType::B), + compIdx * 3 + 1, -1); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(PhaseType::C), + compIdx * 3 + 2, -1); + } else { + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(), + compIdx, -1); + } + + // Apply triplets to the sparse matrix + for (const auto &triplet : triplets) { + mTearTopology.coeffRef(triplet.row(), triplet.col()) += triplet.value(); + } + + // Call tear component stamp function auto tearComp = std::dynamic_pointer_cast(comp); tearComp->mnaTearApplyMatrixStamp(mTearImpedance); } @@ -340,18 +391,85 @@ template <> void DiakopticsSolver::applyTearComponentStamp(UInt compIdx) { auto comp = mTearComponents[compIdx]; - auto net1 = mNodeSubnetMap[comp->node(0)]; - auto net2 = mNodeSubnetMap[comp->node(1)]; + // Use triplets to populate the sparse matrix + std::vector> triplets; + + // Node 0 contributions + if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) { + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(PhaseType::A), + compIdx * 3, 1); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + mNodeSubnetMap[comp->node(0)]->mCmplOff + + comp->node(0)->matrixNodeIndex(PhaseType::A), + mTearComponents.size() * 3 + compIdx * 3, + double(1.0)); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(PhaseType::B), + compIdx * 3 + 1, 1); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + mNodeSubnetMap[comp->node(0)]->mCmplOff + + comp->node(0)->matrixNodeIndex(PhaseType::B), + mTearComponents.size() * 3 + compIdx * 3 + 1, + double(1.0)); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(PhaseType::C), + compIdx * 3 + 2, 1); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + mNodeSubnetMap[comp->node(0)]->mCmplOff + + comp->node(0)->matrixNodeIndex(PhaseType::C), + mTearComponents.size() * 3 + compIdx * 3 + 2, + double(1.0)); + } else { + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + comp->node(0)->matrixNodeIndex(), + compIdx, 1); + triplets.emplace_back(mNodeSubnetMap[comp->node(0)]->sysOff + + mNodeSubnetMap[comp->node(0)]->mCmplOff + + comp->node(0)->matrixNodeIndex(), + mTearComponents.size() + compIdx, double(1.0)); + } - mTearTopology(net1->sysOff + comp->node(0)->matrixNodeIndex(), compIdx) = 1; - mTearTopology(net1->sysOff + net1->mCmplOff + - comp->node(0)->matrixNodeIndex(), - mTearComponents.size() + compIdx) = 1; - mTearTopology(net2->sysOff + comp->node(1)->matrixNodeIndex(), compIdx) = -1; - mTearTopology(net2->sysOff + net2->mCmplOff + - comp->node(1)->matrixNodeIndex(), - mTearComponents.size() + compIdx) = -1; + if (comp->node(0)->phaseType() == CPS::PhaseType::ABC) { + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(PhaseType::A), + compIdx * 3, -1); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + mNodeSubnetMap[comp->node(1)]->mCmplOff + + comp->node(1)->matrixNodeIndex(PhaseType::A), + mTearComponents.size() * 3 + compIdx * 3, + double(-1.0)); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(PhaseType::B), + compIdx * 3 + 1, -1); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + mNodeSubnetMap[comp->node(1)]->mCmplOff + + comp->node(1)->matrixNodeIndex(PhaseType::B), + mTearComponents.size() * 3 + compIdx * 3 + 1, + double(-1.0)); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(PhaseType::C), + compIdx * 3 + 2, -1); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + mNodeSubnetMap[comp->node(1)]->mCmplOff + + comp->node(1)->matrixNodeIndex(PhaseType::C), + mTearComponents.size() * 3 + compIdx * 3 + 2, + double(-1.0)); + } else { + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + comp->node(1)->matrixNodeIndex(), + compIdx, -1); + triplets.emplace_back(mNodeSubnetMap[comp->node(1)]->sysOff + + mNodeSubnetMap[comp->node(1)]->mCmplOff + + comp->node(1)->matrixNodeIndex(), + mTearComponents.size() + compIdx, double(-1.0)); + } + // Apply triplets to the sparse matrix + for (const auto &triplet : triplets) { + mTearTopology.coeffRef(triplet.row(), triplet.col()) += triplet.value(); + } + // Call tear component stamp function auto tearComp = std::dynamic_pointer_cast(comp); tearComp->mnaTearApplyMatrixStamp(mTearImpedance); } @@ -434,8 +552,46 @@ void DiakopticsSolver::SolveTask::execute(Real time, **mSubnet.leftVector = lBlock; } -template -void DiakopticsSolver::PostSolveTask::execute(Real time, +template <> +void DiakopticsSolver::PostSolveTask::execute(Real time, + Int timeStepCount) { + // pass the voltages and current of the solution to the torn components + mSolver.mTearVoltages = + -mSolver.mTearTopology.transpose() * mSolver.mLeftSideVector; + for (UInt compIdx = 0; compIdx < mSolver.mTearComponents.size(); ++compIdx) { + auto comp = mSolver.mTearComponents[compIdx]; + auto tComp = std::dynamic_pointer_cast(comp); + if (mSolver.mPhaseType == CPS::PhaseType::ABC) { + Matrix voltage = Matrix::Zero(3, 1); + voltage << mSolver.mTearVoltages(compIdx * 3), + mSolver.mTearVoltages(compIdx * 3 + 1), + mSolver.mTearVoltages(compIdx * 3 + 2); + + Matrix current = Matrix::Zero(3, 1); + current << mSolver.mTearCurrents(compIdx * 3), + mSolver.mTearCurrents(compIdx * 3 + 1), + mSolver.mTearCurrents(compIdx * 3 + 2); + tComp->mnaTearPostStep(voltage, current); + } else { + Complex voltage = + Math::complexFromVectorElement(mSolver.mTearVoltages, compIdx); + Complex current = + Math::complexFromVectorElement(mSolver.mTearCurrents, compIdx); + tComp->mnaTearPostStep(voltage, current); + } + } + + // TODO split into separate task? (dependent on x, updating all v attributes) + for (UInt net = 0; net < mSolver.mSubnets.size(); ++net) { + for (UInt node = 0; node < mSolver.mSubnets[net].mRealNetNodeNum; ++node) { + mSolver.mSubnets[net].nodes[node]->mnaUpdateVoltage( + *(mSolver.mSubnets[net].leftVector)); + } + } +} + +template <> +void DiakopticsSolver::PostSolveTask::execute(Real time, Int timeStepCount) { // pass the voltages and current of the solution to the torn components mSolver.mTearVoltages = @@ -443,11 +599,29 @@ void DiakopticsSolver::PostSolveTask::execute(Real time, for (UInt compIdx = 0; compIdx < mSolver.mTearComponents.size(); ++compIdx) { auto comp = mSolver.mTearComponents[compIdx]; auto tComp = std::dynamic_pointer_cast(comp); - Complex voltage = - Math::complexFromVectorElement(mSolver.mTearVoltages, compIdx); - Complex current = - Math::complexFromVectorElement(mSolver.mTearCurrents, compIdx); - tComp->mnaTearPostStep(voltage, current); + if (mSolver.mPhaseType == CPS::PhaseType::ABC) { + MatrixComp voltage = MatrixComp::Zero(3, 1); + voltage << Math::complexFromVectorElement(mSolver.mTearVoltages, + compIdx * 3), + Math::complexFromVectorElement(mSolver.mTearVoltages, + compIdx * 3 + 1), + Math::complexFromVectorElement(mSolver.mTearVoltages, + compIdx * 3 + 2); + MatrixComp current = MatrixComp::Zero(3, 1); + current << Math::complexFromVectorElement(mSolver.mTearCurrents, + compIdx * 3), + Math::complexFromVectorElement(mSolver.mTearCurrents, + compIdx * 3 + 1), + Math::complexFromVectorElement(mSolver.mTearCurrents, + compIdx * 3 + 2); + tComp->mnaTearPostStep(voltage, current); + } else { + Complex voltage = + Math::complexFromVectorElement(mSolver.mTearVoltages, compIdx); + Complex current = + Math::complexFromVectorElement(mSolver.mTearCurrents, compIdx); + tComp->mnaTearPostStep(voltage, current); + } } // TODO split into separate task? (dependent on x, updating all v attributes) diff --git a/dpsim/src/InterfaceQueued.cpp b/dpsim/src/InterfaceQueued.cpp index e94e84724e..a820c04082 100644 --- a/dpsim/src/InterfaceQueued.cpp +++ b/dpsim/src/InterfaceQueued.cpp @@ -15,16 +15,19 @@ void InterfaceQueued::open() { mOpened = true; if (!mImportAttrsDpsim.empty()) { - mInterfaceReaderThread = std::thread(InterfaceQueued::ReaderThread(mQueueInterfaceToDpsim, mInterfaceWorker, mOpened)); + mInterfaceReaderThread = std::thread(InterfaceQueued::ReaderThread( + mQueueInterfaceToDpsim, mInterfaceWorker, mOpened)); } if (!mExportAttrsDpsim.empty()) { - mInterfaceWriterThread = std::thread(InterfaceQueued::WriterThread(mQueueDpsimToInterface, mInterfaceWorker)); + mInterfaceWriterThread = std::thread(InterfaceQueued::WriterThread( + mQueueDpsimToInterface, mInterfaceWorker)); } } void InterfaceQueued::close() { mOpened = false; - mQueueDpsimToInterface->emplace(AttributePacket{nullptr, 0, 0, AttributePacketFlags::PACKET_CLOSE_INTERFACE}); + mQueueDpsimToInterface->emplace(AttributePacket{ + nullptr, 0, 0, AttributePacketFlags::PACKET_CLOSE_INTERFACE}); if (!mExportAttrsDpsim.empty()) { mInterfaceWriterThread.join(); @@ -75,48 +78,61 @@ void InterfaceQueued::syncExports() { } void InterfaceQueued::popDpsimAttrsFromQueue(bool isSync) { - AttributePacket receivedPacket = {nullptr, 0, 0, AttributePacketFlags::PACKET_NO_FLAGS}; + AttributePacket receivedPacket = {nullptr, 0, 0, + AttributePacketFlags::PACKET_NO_FLAGS}; UInt currentSequenceId = mNextSequenceInterfaceToDpsim; // Wait for and dequeue all attributes that read should block on // The std::find_if will look for all attributes that have not been updated in the current while loop (i. e. whose sequence ID is lower than the next expected sequence ID) - while (std::find_if(mImportAttrsDpsim.cbegin(), mImportAttrsDpsim.cend(), [currentSequenceId, isSync](auto attrTuple) { - auto &[_attr, seqId, blockOnRead, syncOnStart] = attrTuple; - if (isSync) { - return syncOnStart && seqId < currentSequenceId; - } else { - return blockOnRead && seqId < currentSequenceId; - } - }) != mImportAttrsDpsim.cend()) { + while (std::find_if(mImportAttrsDpsim.cbegin(), mImportAttrsDpsim.cend(), + [currentSequenceId, isSync](auto attrTuple) { + auto &[_attr, seqId, blockOnRead, syncOnStart] = + attrTuple; + if (isSync) { + return syncOnStart && seqId < currentSequenceId; + } else { + return blockOnRead && seqId < currentSequenceId; + } + }) != mImportAttrsDpsim.cend()) { if (mQueueInterfaceToDpsim->try_dequeue(receivedPacket) != false) { int i = 0; while (mQueueInterfaceToDpsim->try_dequeue(receivedPacket)) { i++; } - SPDLOG_LOGGER_WARN(mLog, "Overrun detected! Discarding {} overrun packets!", i); + SPDLOG_LOGGER_WARN(mLog, + "Overrun detected! Discarding {} overrun packets!", i); } else { mQueueInterfaceToDpsim->wait_dequeue(receivedPacket); } - if (!std::get<0>(mImportAttrsDpsim[receivedPacket.attributeId])->copyValue(receivedPacket.value)) { - SPDLOG_LOGGER_WARN(mLog, "Failed to copy received value onto attribute in Interface!"); + if (!std::get<0>(mImportAttrsDpsim[receivedPacket.attributeId]) + ->copyValue(receivedPacket.value)) { + SPDLOG_LOGGER_WARN( + mLog, "Failed to copy received value onto attribute in Interface!"); } - std::get<1>(mImportAttrsDpsim[receivedPacket.attributeId]) = receivedPacket.sequenceId; + std::get<1>(mImportAttrsDpsim[receivedPacket.attributeId]) = + receivedPacket.sequenceId; mNextSequenceInterfaceToDpsim = receivedPacket.sequenceId + 1; } // Fetch all remaining queue packets while (mQueueInterfaceToDpsim->try_dequeue(receivedPacket)) { - if (!std::get<0>(mImportAttrsDpsim[receivedPacket.attributeId])->copyValue(receivedPacket.value)) { - SPDLOG_LOGGER_WARN(mLog, "Failed to copy received value onto attribute in Interface!"); + if (!std::get<0>(mImportAttrsDpsim[receivedPacket.attributeId]) + ->copyValue(receivedPacket.value)) { + SPDLOG_LOGGER_WARN( + mLog, "Failed to copy received value onto attribute in Interface!"); } - std::get<1>(mImportAttrsDpsim[receivedPacket.attributeId]) = receivedPacket.sequenceId; + std::get<1>(mImportAttrsDpsim[receivedPacket.attributeId]) = + receivedPacket.sequenceId; mNextSequenceInterfaceToDpsim = receivedPacket.sequenceId + 1; } } void InterfaceQueued::pushDpsimAttrsToQueue() { for (UInt i = 0; i < mExportAttrsDpsim.size(); i++) { - mQueueDpsimToInterface->emplace(AttributePacket{std::get<0>(mExportAttrsDpsim[i])->cloneValueOntoNewAttribute(), i, std::get<1>(mExportAttrsDpsim[i]), AttributePacketFlags::PACKET_NO_FLAGS}); + mQueueDpsimToInterface->emplace(AttributePacket{ + std::get<0>(mExportAttrsDpsim[i])->cloneValueOntoNewAttribute(), i, + std::get<1>(mExportAttrsDpsim[i]), + AttributePacketFlags::PACKET_NO_FLAGS}); std::get<1>(mExportAttrsDpsim[i]) = mCurrentSequenceDpsimToInterface; mCurrentSequenceDpsimToInterface++; } @@ -126,7 +142,8 @@ void InterfaceQueued::WriterThread::operator()() const { bool interfaceClosed = false; std::vector attrsToWrite; while (!interfaceClosed) { - AttributePacket nextPacket = {nullptr, 0, 0, AttributePacketFlags::PACKET_NO_FLAGS}; + AttributePacket nextPacket = {nullptr, 0, 0, + AttributePacketFlags::PACKET_NO_FLAGS}; // Wait for at least one packet mQueueDpsimToInterface->wait_dequeue(nextPacket); diff --git a/dpsim/src/KLUAdapter.cpp b/dpsim/src/KLUAdapter.cpp index ed79b4327c..81fbd91b5e 100644 --- a/dpsim/src/KLUAdapter.cpp +++ b/dpsim/src/KLUAdapter.cpp @@ -61,13 +61,27 @@ void KLUAdapter::preprocessing( mVaryingColumns.push_back(changedEntry.second); } - // this call also works if mVaryingColumns, mVaryingRows are empty - mSymbolic = - klu_analyze_partial(n, Ap, Ai, &mVaryingColumns[0], &mVaryingRows[0], - varying_entries, mPreordering, &mCommon); + // This call also works if mVaryingColumns, mVaryingRows are empty + int *colPtr = mVaryingColumns.empty() ? nullptr : &mVaryingColumns[0]; + int *rowPtr = mVaryingRows.empty() ? nullptr : &mVaryingRows[0]; - /* store non-zero value of current preprocessed matrix. only used until - * to-do in refactorize-function is resolved. Can be removed then. */ + mSymbolic = klu_analyze_partial(n, Ap, Ai, colPtr, rowPtr, varying_entries, + mPreordering, &mCommon); + + if (mVaryingColumns.empty()) { + SPDLOG_LOGGER_INFO( + mSLog, + "KLUAdapter: No variable COLUMN entries passed to klu_analyze_partial"); + } + if (mVaryingRows.empty()) { + SPDLOG_LOGGER_INFO( + mSLog, + "KLUAdapter: No variable ROW entries passed to klu_analyze_partial"); + } + + /* Store non-zero value of current preprocessed matrix. only used until + * to-do in refactorize-function is resolved. Can be removed then. + */ nnz = Eigen::internal::convert_index(systemMatrix.nonZeros()); } @@ -85,8 +99,9 @@ void KLUAdapter::factorize(SparseMatrix &systemMatrix) { Int varying_entries = Eigen::internal::convert_index(mChangedEntries.size()); - /* make sure that factorization path is not computed if there are no varying entries. - * Doing so should not be a problem, but it is safer to do it this way */ + /* Make sure that factorization path is not computed if there are no varying entries. + * Doing so should not be a problem, but it is safer to do it this way. + */ if (!(mVaryingColumns.empty()) && !(mVaryingRows.empty())) { if (mPartialRefactorizationMethod == DPsim::PARTIAL_REFACTORIZATION_METHOD::FACTORIZATION_PATH) { @@ -102,7 +117,7 @@ void KLUAdapter::factorize(SparseMatrix &systemMatrix) { } void KLUAdapter::refactorize(SparseMatrix &systemMatrix) { - /* TODO: remove if-else when zero<->non-zero issue during matrix stamping has been fixed. Also remove in partialRefactorize then. */ + // TODO: Remove if-else when zero<->non-zero issue during matrix stamping has been fixed. Also remove in partialRefactorize then. if (systemMatrix.nonZeros() != nnz) { preprocessing(systemMatrix, mChangedEntries); factorize(systemMatrix); @@ -153,16 +168,18 @@ Matrix KLUAdapter::solve(Matrix &rightSideVector) { // We should preallocate this buffer. Matrix x = rightSideVector; - /* number of right hands sides - * usually one, KLU can handle multiple right hand sides */ + /* Number of right hands sides + * usually one, KLU can handle multiple right hand sides. + */ Int rhsCols = Eigen::internal::convert_index(rightSideVector.cols()); - /* leading dimension, also called "n" */ + // Leading dimension, also called "n". Int rhsRows = Eigen::internal::convert_index(rightSideVector.rows()); /* tsolve refers to transpose solve. Input matrix is stored in compressed row format, - * KLU operates on compressed column format. This way, the transpose of the matrix is factored. - * This has to be taken into account only here during right-hand solving. */ + * KLU operates on compressed column format. This way, the transpose of the matrix is factored. + * This has to be taken into account only here during right-hand solving. + */ klu_tsolve(mSymbolic, mNumeric, rhsRows, rhsCols, x.const_cast_derived().data(), &mCommon); @@ -180,8 +197,9 @@ void KLUAdapter::printMatrixMarket(SparseMatrix &matrix, int counter) const { std::ofstream ofs; ofs.open(outputName); - /* TODO: add logger to DirectLinearSolver to use libfmt's more powerful logging tools. - * Then also move matrix printing (of LU matrices) here in order to avoid C-level printing. */ + /* TODO: Add logger to DirectLinearSolver to use libfmt's more powerful logging tools. + * Then also move matrix printing (of LU matrices) here in order to avoid C-level printing. + */ ofs.precision(14); ofs << "%%MatrixMarket matrix coordinate real general" << std::endl; ofs << n << " " << n << " " << nz << std::endl; @@ -211,7 +229,7 @@ void KLUAdapter::applyConfiguration() { SPDLOG_LOGGER_INFO(mSLog, "Matrix is scaled using " + mConfiguration.getScalingMethodString()); - // TODO: implement support for COLAMD (modifiy SuiteSparse) + // TODO: Implement support for COLAMD (modifiy SuiteSparse) switch (mConfiguration.getFillInReductionMethod()) { case FILL_IN_REDUCTION_METHOD::AMD: mPreordering = AMD_ORDERING; diff --git a/dpsim/src/MNASolverDirect.cpp b/dpsim/src/MNASolverDirect.cpp index 1088db00a5..40b33ad681 100644 --- a/dpsim/src/MNASolverDirect.cpp +++ b/dpsim/src/MNASolverDirect.cpp @@ -78,12 +78,7 @@ void MnaSolverDirect::stampVariableSystemMatrix() { // Continue from base matrix mVariableSystemMatrix = mBaseSystemMatrix; - // Now stamp switches into matrix - SPDLOG_LOGGER_INFO(mSLog, "Stamping switches"); - for (auto sw : mMNAIntfSwitches) - sw->mnaApplySystemMatrixStamp(mVariableSystemMatrix); - - // Now stamp initial state of variable elements into matrix + // Now stamp initial state of variable elements and switches into matrix SPDLOG_LOGGER_INFO(mSLog, "Stamping variable elements"); for (auto varElem : mMNAIntfVariableComps) varElem->mnaApplySystemMatrixStamp(mVariableSystemMatrix); @@ -139,11 +134,7 @@ void MnaSolverDirect::recomputeSystemMatrix(Real time) { // Start from base matrix mVariableSystemMatrix = mBaseSystemMatrix; - // Now stamp switches into matrix - for (auto sw : mMNAIntfSwitches) - sw->mnaApplySystemMatrixStamp(mVariableSystemMatrix); - - // Now stamp variable elements into matrix + // Now stamp variable elements and switches into matrix for (auto comp : mMNAIntfVariableComps) comp->mnaApplySystemMatrixStamp(mVariableSystemMatrix); diff --git a/dpsim/src/MNASolverPlugin.cpp b/dpsim/src/MNASolverPlugin.cpp index e23cf9ce58..13ce9005b2 100644 --- a/dpsim/src/MNASolverPlugin.cpp +++ b/dpsim/src/MNASolverPlugin.cpp @@ -35,7 +35,7 @@ template MnaSolverPlugin::~MnaSolverPlugin() { extern "C" void pluginLogger(const char *str) { CPS::Logger::Log log = CPS::Logger::get("Plugin", CPS::Logger::Level::debug, CPS::Logger::Level::debug); - log->info(str); + SPDLOG_LOGGER_INFO(log, str); } template @@ -75,7 +75,8 @@ template void MnaSolverPlugin::initialize() { std::vector hMat; int nnz = 0; if (this->mSystemMatrixRecomputation) { - SPDLOG_LOGGER_ERROR(this->mSLog, "System matrix recomputation not supported"); + SPDLOG_LOGGER_ERROR(this->mSLog, + "System matrix recomputation not supported"); return; } else { hMat = this->mSwitchedMatrices[std::bitset(0)]; diff --git a/dpsim/src/ODESolver.cpp b/dpsim/src/ODESolver.cpp index 53a1ba2eb0..eaaf8af833 100644 --- a/dpsim/src/ODESolver.cpp +++ b/dpsim/src/ODESolver.cpp @@ -37,54 +37,6 @@ void ODESolver::initialize() { double tmp1[], double tmp2[], double tmp3[]) { dummy->odeJacobian(t, y, fy, J, tmp1, tmp2, tmp3); }; - - // Causes numerical issues, better allocate in every step-> see step - /*mArkode_mem= ARKodeCreate(); - if (check_flag(mArkode_mem, "ARKodeCreate", 0)) - mFlag=1; - - mFlag = ARKodeSetUserData(mArkode_mem, this); - if (check_flag(&mFlag, "ARKodeSetUserData", 1)) - mFlag=1;*/ - - /* Call ARKodeInit to initialize the integrator memory and specify the - right-hand side function in y'=f(t,y), the inital time T0, and - the initial dependent variable vector y(fluxes+mech. vars).*/ - /* if(mImplicitIntegration){ - mFlag = ARKodeInit(mArkode_mem, NULL, &ODESolver::StateSpaceWrapper, initial_time, mStates); - if (check_flag(&mFlag, "ARKodeInit", 1)) throw CPS::Exception(); - - // Initialize dense matrix data structure - A = SUNDenseMatrix(mProbDim, mProbDim); - if (check_flag((void *)A, "SUNDenseMatrix", 0)) throw CPS::Exception(); - - // Initialize linear solver - LS = SUNDenseLinearSolver(mStates, A); - if (check_flag((void *)LS, "SUNDenseLinearSolver", 0)) throw CPS::Exception(); - - // Attach matrix and linear solver - mFlag = ARKDlsSetLinearSolver(mArkode_mem, LS, A); - if (check_flag(&mFlag, "ARKDlsSetLinearSolver", 1)) throw CPS::Exception(); - - // Set Jacobian routine - mFlag = ARKDlsSetJacFn(mArkode_mem, &ODESolver::JacobianWrapper); - if (check_flag(&mFlag, "ARKDlsSetJacFn", 1)) throw CPS::Exception(); - } - else { - mFlag = ARKodeInit(mArkode_mem, &ODESolver::StateSpaceWrapper, NULL, initial_time, mStates); - if (check_flag(&mFlag, "ARKodeInit", 1)) throw CPS::Exception(); - }*/ - - // Shifted to every step because of numerical issues - - // Specify Runge-Kutta Method/order - /*mFlag = ARKodeSetOrder(mArkode_mem, 4); - if (check_flag(&mFlag, "ARKodeOrderSet", 1)) - mFlag=1;*/ - - /*mFlag = ARKodeSStolerances(mArkode_mem, reltol, abstol); - if (check_flag(&mFlag, "ARKodeSStolerances", 1)) - mFlag=1;*/ } int ODESolver::StateSpaceWrapper(realtype t, N_Vector y, N_Vector ydot, @@ -134,8 +86,9 @@ Real ODESolver::step(Real initial_time) { mFlag = 1; /* Call ARKodeInit to initialize the integrator memory and specify the - right-hand side function in y'=f(t,y), the inital time T0, and - the initial dependent variable vector y(fluxes+mech. vars).*/ + * right-hand side function in y'=f(t,y), the inital time T0, and + * the initial dependent variable vector y(fluxes+mech. vars). + */ if (mImplicitIntegration) { mFlag = ARKodeInit(mArkode_mem, NULL, &ODESolver::StateSpaceWrapper, initial_time, mStates); diff --git a/dpsim/src/PFSolver.cpp b/dpsim/src/PFSolver.cpp index e6aad98821..c4026ee483 100644 --- a/dpsim/src/PFSolver.cpp +++ b/dpsim/src/PFSolver.cpp @@ -185,48 +185,48 @@ void PFSolver::determinePFBusType() { // determine powerflow bus types according connected type of connected components // only PQ type component connected -> set as PQ bus if (!connectedPV && connectedPQ && !connectedVD) { - SPDLOG_LOGGER_DEBUG( + SPDLOG_LOGGER_INFO( mSLog, "{}: only PQ type component connected -> set as PQ bus", node->name()); mPQBusIndices.push_back(node->matrixNodeIndex()); mPQBuses.push_back(node); } // no component connected -> set as PQ bus (P & Q will be zero) else if (!connectedPV && !connectedPQ && !connectedVD) { - SPDLOG_LOGGER_DEBUG(mSLog, "{}: no component connected -> set as PQ bus", - node->name()); + SPDLOG_LOGGER_INFO(mSLog, "{}: no component connected -> set as PQ bus", + node->name()); mPQBusIndices.push_back(node->matrixNodeIndex()); mPQBuses.push_back(node); } // only PV type component connected -> set as PV bus else if (connectedPV && !connectedPQ && !connectedVD) { - SPDLOG_LOGGER_DEBUG( + SPDLOG_LOGGER_INFO( mSLog, "{}: only PV type component connected -> set as PV bus", node->name()); mPVBusIndices.push_back(node->matrixNodeIndex()); mPVBuses.push_back(node); } // PV and PQ type component connected -> set as PV bus (TODO: bus type should be modifiable by user afterwards) else if (connectedPV && connectedPQ && !connectedVD) { - SPDLOG_LOGGER_DEBUG( + SPDLOG_LOGGER_INFO( mSLog, "{}: PV and PQ type component connected -> set as PV bus", node->name()); mPVBusIndices.push_back(node->matrixNodeIndex()); mPVBuses.push_back(node); } // only VD type component connected -> set as VD bus else if (!connectedPV && !connectedPQ && connectedVD) { - SPDLOG_LOGGER_DEBUG( + SPDLOG_LOGGER_INFO( mSLog, "{}: only VD type component connected -> set as VD bus", node->name()); mVDBusIndices.push_back(node->matrixNodeIndex()); mVDBuses.push_back(node); } // VD and PV type component connect -> set as VD bus else if (connectedPV && !connectedPQ && connectedVD) { - SPDLOG_LOGGER_DEBUG( + SPDLOG_LOGGER_INFO( mSLog, "{}: VD and PV type component connect -> set as VD bus", node->name()); mVDBusIndices.push_back(node->matrixNodeIndex()); mVDBuses.push_back(node); } // VD, PV and PQ type component connect -> set as VD bus else if (connectedPV && connectedPQ && connectedVD) { - SPDLOG_LOGGER_DEBUG( + SPDLOG_LOGGER_INFO( mSLog, "{}: VD, PV and PQ type component connect -> set as VD bus", node->name()); mVDBusIndices.push_back(node->matrixNodeIndex()); @@ -269,8 +269,7 @@ void PFSolver::determineNodeBaseVoltages() { if (std::shared_ptr vsi = std::dynamic_pointer_cast< CPS::SP::Ph1::AvVoltageSourceInverterDQ>(comp)) { - baseVoltage_ = - Math::abs(vsi->attributeTyped("vnom")->get()); + baseVoltage_ = vsi->getNomVoltage(); SPDLOG_LOGGER_INFO( mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", @@ -278,7 +277,7 @@ void PFSolver::determineNodeBaseVoltages() { break; } else if (std::shared_ptr rxline = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = rxline->attributeTyped("base_Voltage")->get(); + baseVoltage_ = rxline->getBaseVoltage(); SPDLOG_LOGGER_INFO( mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", @@ -286,7 +285,7 @@ void PFSolver::determineNodeBaseVoltages() { break; } else if (std::shared_ptr line = std::dynamic_pointer_cast(comp)) { - baseVoltage_ = line->attributeTyped("base_Voltage")->get(); + baseVoltage_ = line->getBaseVoltage(); SPDLOG_LOGGER_INFO( mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", @@ -296,16 +295,14 @@ void PFSolver::determineNodeBaseVoltages() { std::dynamic_pointer_cast( comp)) { if (trans->terminal(0)->node()->name() == node->name()) { - baseVoltage_ = - trans->attributeTyped("nominal_voltage_end1")->get(); + baseVoltage_ = trans->getNominalVoltageEnd1(); SPDLOG_LOGGER_INFO( mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, trans->name(), node->name()); break; } else if (trans->terminal(1)->node()->name() == node->name()) { - baseVoltage_ = - trans->attributeTyped("nominal_voltage_end2")->get(); + baseVoltage_ = trans->getNominalVoltageEnd2(); SPDLOG_LOGGER_INFO( mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", @@ -315,12 +312,27 @@ void PFSolver::determineNodeBaseVoltages() { } else if (std::shared_ptr gen = std::dynamic_pointer_cast( comp)) { - baseVoltage_ = gen->attributeTyped("base_Voltage")->get(); + baseVoltage_ = gen->getBaseVoltage(); SPDLOG_LOGGER_INFO( mSLog, "Choose base voltage {}V of {} to convert pu-solution of {}.", baseVoltage_, gen->name(), node->name()); break; + } else if (std::shared_ptr load = + std::dynamic_pointer_cast(comp)) { + baseVoltage_ = load->getNomVoltage(); + SPDLOG_LOGGER_INFO( + mSLog, "Choose base voltage of {} V to convert pu-solution of {}.", + baseVoltage_, load->name(), node->name()); + break; + } else if (std::shared_ptr extnet = + std::dynamic_pointer_cast( + comp)) { + baseVoltage_ = extnet->getBaseVoltage(); + SPDLOG_LOGGER_INFO( + mSLog, "Choose base voltage of {}V to convert pu-solution of {}.", + baseVoltage_, extnet->name(), node->name()); + break; } else { SPDLOG_LOGGER_WARN(mSLog, "Unable to get base voltage at {}", node->name()); diff --git a/dpsim/src/PFSolverPowerPolar.cpp b/dpsim/src/PFSolverPowerPolar.cpp index 0ab6368019..87e014af1e 100644 --- a/dpsim/src/PFSolverPowerPolar.cpp +++ b/dpsim/src/PFSolverPowerPolar.cpp @@ -62,6 +62,13 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, vsi->attributeTyped("P_ref")->get() / mBaseApparentPower; sol_Q(pq->matrixNodeIndex()) += vsi->attributeTyped("Q_ref")->get() / mBaseApparentPower; + } else if (std::shared_ptr gen = + std::dynamic_pointer_cast( + comp)) { + sol_P(pq->matrixNodeIndex()) += + gen->attributeTyped("P_set_pu")->get(); + sol_Q(pq->matrixNodeIndex()) += + gen->attributeTyped("Q_set_pu")->get(); } sol_S_complex(pq->matrixNodeIndex()) = CPS::Complex( sol_P[pq->matrixNodeIndex()], sol_Q[pq->matrixNodeIndex()]); @@ -81,10 +88,14 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, gen->attributeTyped("P_set_pu")->get(); sol_V(pv->matrixNodeIndex()) = gen->attributeTyped("V_set_pu")->get(); + sol_Q(pv->matrixNodeIndex()) += + gen->attributeTyped("Q_set_pu")->get(); } else if (std::shared_ptr load = std::dynamic_pointer_cast(comp)) { sol_P(pv->matrixNodeIndex()) -= load->attributeTyped("P_pu")->get(); + sol_Q(pv->matrixNodeIndex()) -= + load->attributeTyped("Q_pu")->get(); } else if (std::shared_ptr vsi = std::dynamic_pointer_cast< CPS::SP::Ph1::AvVoltageSourceInverterDQ>(comp)) { @@ -96,6 +107,9 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, sol_P(pv->matrixNodeIndex()) += extnet->attributeTyped("p_inj")->get() / mBaseApparentPower; + sol_Q(pv->matrixNodeIndex()) += + extnet->attributeTyped("q_inj")->get() / + mBaseApparentPower; sol_V(pv->matrixNodeIndex()) = extnet->attributeTyped("V_set_pu")->get(); } diff --git a/dpsim/src/RealTimeDataLogger.cpp b/dpsim/src/RealTimeDataLogger.cpp index a071d19c57..97c5f818c9 100644 --- a/dpsim/src/RealTimeDataLogger.cpp +++ b/dpsim/src/RealTimeDataLogger.cpp @@ -4,25 +4,38 @@ * SPDX-FileCopyrightText: 2024 Niklas Eiling * SPDX-License-Identifier: Apache-2.0 */ -#include "dpsim-models/Attribute.h" + #include +#include -#include #include -#include + +#include +#include using namespace DPsim; -RealTimeDataLogger::RealTimeDataLogger(std::filesystem::path &filename, size_t rowNumber) - : DataLoggerInterface(), mFilename(filename), mRowNumber(rowNumber), mCurrentRow(0), mCurrentAttribute(0), mAttributeData() {} +RealTimeDataLogger::RealTimeDataLogger(std::filesystem::path &filename, + size_t rowNumber) + : DataLoggerInterface(), mFilename(filename), mRowNumber(rowNumber), + mCurrentRow(0), mCurrentAttribute(0), mAttributeData() {} -RealTimeDataLogger::RealTimeDataLogger(std::filesystem::path &filename, Real finalTime, Real timeStep) - : DataLoggerInterface(), mFilename(filename), mRowNumber((finalTime / timeStep + 0.5)), mCurrentRow(0), mCurrentAttribute(0), mAttributeData() {} +RealTimeDataLogger::RealTimeDataLogger(std::filesystem::path &filename, + Real finalTime, Real timeStep) + : DataLoggerInterface(), mFilename(filename), + mRowNumber((finalTime / timeStep + 0.5)), mCurrentRow(0), + mCurrentAttribute(0), mAttributeData() {} void RealTimeDataLogger::start() { - double mb_size = static_cast(mRowNumber) * (mAttributes.size() + 1) * sizeof(Real); - auto log = CPS::Logger::get("RealTimeDataLogger", CPS::Logger::Level::off, CPS::Logger::Level::info); - log->info("Preallocating memory for real-time data logger: {} rows for {} attributes ({} MB)", mRowNumber, mAttributes.size(), mb_size / (1024 * 1024)); + double mb_size = + static_cast(mRowNumber) * (mAttributes.size() + 1) * sizeof(Real); + auto log = CPS::Logger::get("RealTimeDataLogger", CPS::Logger::Level::off, + CPS::Logger::Level::info); + SPDLOG_LOGGER_INFO( + log, + "Preallocating memory for real-time data logger: {} rows for {} " + "attributes ({} MB)", + mRowNumber, mAttributes.size(), mb_size / (1024 * 1024)); // We are doing real time so preallocate everything mAttributeData.resize(mRowNumber); for (auto &it : mAttributeData) { @@ -32,7 +45,24 @@ void RealTimeDataLogger::start() { } void RealTimeDataLogger::stop() { - auto mLogFile = std::ofstream(mFilename, std::ios_base::out | std::ios_base::trunc); + auto log = CPS::Logger::get("RealTimeDataLogger", CPS::Logger::Level::off, + CPS::Logger::Level::info); + SPDLOG_LOGGER_INFO( + log, "Stopping real-time data logger. Writing memory to file {}", + mFilename.string()); + + const auto parent = mFilename.parent_path(); + if (!parent.empty()) { + std::error_code ec; + std::filesystem::create_directories(parent, ec); + if (ec) { + throw std::runtime_error("Cannot create log directory '" + + parent.string() + "': " + ec.message()); + } + } + + auto mLogFile = + std::ofstream(mFilename, std::ios_base::out | std::ios_base::trunc); if (!mLogFile.is_open()) { throw std::runtime_error("Cannot open log file " + mFilename.string()); } @@ -49,28 +79,48 @@ void RealTimeDataLogger::stop() { mLogFile << '\n'; } mLogFile.close(); + SPDLOG_LOGGER_INFO(log, "Finished writing real-time data log to file {}", + mFilename.string()); } void RealTimeDataLogger::log(Real time, Int timeStepCount) { mCurrentRow = timeStepCount; if (timeStepCount < 0 || static_cast(timeStepCount) >= mRowNumber) { - throw std::runtime_error("RealTimeDataLogger: timeStepCount out of bounds. Please verify the logger was initialized correctly."); + throw std::runtime_error( + "RealTimeDataLogger: timeStepCount out of bounds. Please verify the " + "logger was initialized correctly."); } - if (mAttributeData.size() != mRowNumber || mAttributeData[mCurrentRow].size() != mAttributes.size() + 1) { - throw std::runtime_error("RealTimeDataLogger: Attribute data size mismatch"); + if (mAttributeData.size() != mRowNumber || + mAttributeData[mCurrentRow].size() != mAttributes.size() + 1) { + throw std::runtime_error( + "RealTimeDataLogger: Attribute data size mismatch"); } mAttributeData[mCurrentRow][0] = time; mCurrentAttribute = 1; - for (auto it : mAttributes) { + for (auto &it : mAttributes) { + auto base = it.second.getPtr(); // std::shared_ptr + if (it.second->getType() == typeid(Real)) { - mAttributeData[mCurrentRow][mCurrentAttribute++] = **std::dynamic_pointer_cast>>(it.second.getPtr()); + auto attr = std::dynamic_pointer_cast>(base); + if (!attr) { /* skip */ + continue; + } + mAttributeData[mCurrentRow][mCurrentAttribute++] = attr->get(); } else if (it.second->getType() == typeid(Int)) { - mAttributeData[mCurrentRow][mCurrentAttribute++] = **std::dynamic_pointer_cast>>(it.second.getPtr()); + auto attr = std::dynamic_pointer_cast>(base); + if (!attr) { /* skip */ + continue; + } + mAttributeData[mCurrentRow][mCurrentAttribute++] = attr->get(); } } } -void RealTimeDataLogger::Step::execute(Real time, Int timeStepCount) { mLogger.log(time, timeStepCount); } +void RealTimeDataLogger::Step::execute(Real time, Int timeStepCount) { + mLogger.log(time, timeStepCount); +} -CPS::Task::Ptr RealTimeDataLogger::getTask() { return std::make_shared(*this); } +CPS::Task::Ptr RealTimeDataLogger::getTask() { + return std::make_shared(*this); +} diff --git a/dpsim/src/RealTimeSimulation.cpp b/dpsim/src/RealTimeSimulation.cpp index 1d64f54a69..8b979f1c1d 100644 --- a/dpsim/src/RealTimeSimulation.cpp +++ b/dpsim/src/RealTimeSimulation.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace CPS; using namespace DPsim; @@ -42,12 +43,10 @@ void RealTimeSimulation::run(const Timer::StartClock::time_point &startAt) { sync(); - auto now_time = std::chrono::system_clock::to_time_t(startAt); - SPDLOG_LOGGER_INFO(mLog, "Starting simulation at {} (delta_T = {} seconds)", - std::put_time(std::localtime(&now_time), "%F %T"), - std::chrono::duration_cast( - startAt - Timer::StartClock::now()) - .count()); + SPDLOG_LOGGER_INFO( + mLog, + "Starting simulation at {:%Y-%m-%d %H:%M:%S} (delta_T = {} seconds)", + startAt, startAt - Timer::StartClock::now()); mTimer.setStartTime(startAt); mTimer.setInterval(**mTimeStep); diff --git a/dpsim/src/Simulation.cpp b/dpsim/src/Simulation.cpp index ce6834bed4..55646c97c9 100644 --- a/dpsim/src/Simulation.cpp +++ b/dpsim/src/Simulation.cpp @@ -223,36 +223,6 @@ Graph::Graph Simulation::dependencyGraph() { std::map avgTimes; std::map fillColors; - /* The main SolveTasks of each Solver usually takes the - * largest amount of computing time. We exclude it from - * coloring for improving the spread of the color range - * for the remaining tasks. - */ - // auto isSolveTask = [](Task::Ptr task) -> Bool { - // const std::vector ignoreTasks = { - // #ifdef WITH_SUNDIALS - // std::type_index(typeid(ODESolver::SolveTask)), - // #endif - // std::type_index(typeid(MnaSolver::SolveTask)), - // std::type_index(typeid(MnaSolver::SolveTask)), - // std::type_index(typeid(DiakopticsSolver::SubnetSolveTask)), - // std::type_index(typeid(DiakopticsSolver::SubnetSolveTask)), - // std::type_index(typeid(DiakopticsSolver::SolveTask)), - // std::type_index(typeid(DiakopticsSolver::SolveTask)), - // std::type_index(typeid(NRpolarSolver::SolveTask)) - // }; - - // return std::find(ignoreTasks.begin(), ignoreTasks.end(), std::type_index(typeid(*task.get()))) != ignoreTasks.end(); - // }; - - // auto isIgnoredTask = [&isSolveTask](Task::Ptr task) -> Bool { - // return typeid(*task.get()) == typeid(Interface::PreStep) || sSolveTask(task); - // }; - - // auto isRootTask = [](Task::Ptr task) -> Bool { - // return typeid(*task.get()) == typeid(Scheduler::Root); - // }; - auto isScheduled = [this](Task::Ptr task) -> Bool { return !mTaskOutEdges[task].empty(); }; @@ -307,12 +277,6 @@ Graph::Graph Simulation::dependencyGraph() { n->set("style", "rounded,filled,bold"); n->set("shape", "rectangle"); - // if (isSolveTask(task)) { - // n->set("fillcolor", "orange"); - // } - // if (isRootTask(task)) { - // n->set("fillcolor", "springgreen1"); - // } if (isScheduled(task)) { if (avgTimeWorst > Scheduler::TaskTime(0)) { auto grad = (float)avgTimes[task].count() / avgTimeWorst.count(); @@ -433,12 +397,12 @@ void Simulation::logStepTimes(String logName) { return; } Logger::setLogPattern(stepTimeLog, "%v"); - stepTimeLog->info("step_time"); + SPDLOG_LOGGER_INFO(stepTimeLog, "step_time"); Real stepTimeSum = 0; for (auto meas : mStepTimes) { stepTimeSum += meas; - stepTimeLog->info("{:.9f}", meas); + SPDLOG_LOGGER_INFO(stepTimeLog, "{:.9f}", meas); } SPDLOG_LOGGER_INFO(mLog, "Average step time: {:.9f}", stepTimeSum / mStepTimes.size()); @@ -447,7 +411,7 @@ void Simulation::logStepTimes(String logName) { void Simulation::checkForOverruns(String logName) { auto stepTimeLog = Logger::get(logName, Logger::Level::info); Logger::setLogPattern(stepTimeLog, "%v"); - stepTimeLog->info("overruns"); + SPDLOG_LOGGER_INFO(stepTimeLog, "overruns"); int overruns = 0; for (auto meas : mStepTimes) { diff --git a/dpsim/src/SolverPlugins/example/Makefile b/dpsim/src/SolverPlugins/example/Makefile index ba63af42a9..c525cacb7f 100644 --- a/dpsim/src/SolverPlugins/example/Makefile +++ b/dpsim/src/SolverPlugins/example/Makefile @@ -6,7 +6,7 @@ CC = gcc all: plugin.so %.o : %.c - $(CC) $(CC_FLAGS) -I../../../Include -c -fpic -o $@ $< + $(CC) $(CC_FLAGS) -I../../../include -c -fpic -o $@ $< plugin.so: example.o $(CC) $(LD_FLAGS) -shared -o $@ $< diff --git a/dpsim/src/SolverPlugins/example/example.c b/dpsim/src/SolverPlugins/example/example.c index 4c82eff6e7..d8e06ec06c 100644 --- a/dpsim/src/SolverPlugins/example/example.c +++ b/dpsim/src/SolverPlugins/example/example.c @@ -9,7 +9,7 @@ int example_solve(double *rhs_values, double *lhs_values); void example_log(const char *str); void example_cleanup(void); -static const char *PLUGIN_NAME = "plugin.so"; +static const char *PLUGIN_NAME = "plugin"; static struct dpsim_mna_plugin example_plugin = { .log = example_log, //a properly working dpsim will override this with the spdlog logger diff --git a/dpsim/src/SolverPlugins/magma/Makefile b/dpsim/src/SolverPlugins/magma/Makefile index 17d61434ef..a42f69875e 100644 --- a/dpsim/src/SolverPlugins/magma/Makefile +++ b/dpsim/src/SolverPlugins/magma/Makefile @@ -9,7 +9,7 @@ LD_FLAGS += -g -lmagma -lmagma_sparse all: libdps_magma.so %.o : %.c - $(CC) $(CC_FLAGS) -I../../../Include -c -fpic -o $@ $< + $(CC) $(CC_FLAGS) -I../../../include -c -fpic -o $@ $< libdps_magma.so: magma.o - $(CC) -shared -o $@ $< $(LD_FLAGS) + $(CC) -shared -o $@ $< $(LD_FLAGS) diff --git a/dpsim/src/Timer.cpp b/dpsim/src/Timer.cpp index 00f0f65a7d..73c9390878 100644 --- a/dpsim/src/Timer.cpp +++ b/dpsim/src/Timer.cpp @@ -15,27 +15,36 @@ #ifdef HAVE_TIMERFD #include #include -#endif /* HAVE_TIMERFD */ +#endif // HAVE_TIMERFD using namespace DPsim; using CPS::SystemError; -Timer::Timer(int flags) - : mState(stopped), mOverruns(0), mTicks(0), mFlags(flags) { +Timer::Timer(int flags, CPS::Logger::Level logLevel) + : mState(stopped), mOverruns(0), mTicks(0), mFlags(flags), + mLogLevel(logLevel) { + mSLog = CPS::Logger::get("Timer"); #ifdef HAVE_TIMERFD mTimerFd = timerfd_create(CLOCK_MONOTONIC, 0); if (mTimerFd < 0) { + SPDLOG_LOGGER_ERROR(mSLog, "Failed to create timerfd"); throw SystemError("Failed to create timerfd"); } #else - std::cerr << "WARNING: No high resolution timer available. Clock might drift!" - << std::endl; + SPDLOG_LOGGER_WARN(mSLog, + "No high resolution timer available. Clock might drift!"); #endif } Timer::~Timer() { if (mState == State::running) - stop(); + try { + stop(); + } catch (SystemError &e) { + SPDLOG_LOGGER_ERROR(mSLog, + "The timer was not stopped properly. The simulation " + "behaviour is not guaranteed anymore."); + } #ifdef HAVE_TIMERFD close(mTimerFd); @@ -50,6 +59,7 @@ void Timer::sleep() { bytes = read(mTimerFd, &ticks, sizeof(ticks)); if (bytes < 0) { + SPDLOG_LOGGER_ERROR(mSLog, "Read from timerfd failed"); throw SystemError("Read from timerfd failed"); } #else @@ -69,9 +79,13 @@ void Timer::sleep() { mTicks += ticks; if (overruns > 0) { - //SPDLOG_LOGGER_WARN(mSLog, "Timer overrun of {} timesteps at {}", overruns, mTime); - if (mFlags & Flags::fail_on_overrun) + SPDLOG_LOGGER_WARN(mSLog, "Timer overrun of {} timesteps at {}", overruns, + mTicks); + if (mFlags & Flags::fail_on_overrun) { + SPDLOG_LOGGER_ERROR(mSLog, "The overrun has made the simulation to fail " + "because the flag is active"); throw OverrunException{overruns}; + } } } @@ -81,14 +95,14 @@ void Timer::start() { mTicks = 0; mOverruns = 0; - /* Determine offset between clocks */ + // Determine offset between clocks. auto rt = StartClock::now(); auto steady = IntervalClock::now(); /* This handles the offset between - * - IntervalClock (CLOCK_MONOTONIC aka std::chrono::steady_clock) and - * - StartClock (CLOCK_REALTIME aka std::chrono::system_clock) - */ + * - IntervalClock (CLOCK_MONOTONIC aka std::chrono::steady_clock) and + * - StartClock (CLOCK_REALTIME aka std::chrono::system_clock) + */ auto start = mStartAt > StartTimePoint() ? mStartAt.time_since_epoch() - rt.time_since_epoch() + steady.time_since_epoch() diff --git a/dpsim/src/Utils.cpp b/dpsim/src/Utils.cpp index c3a04701fb..1619d1c411 100644 --- a/dpsim/src/Utils.cpp +++ b/dpsim/src/Utils.cpp @@ -427,6 +427,7 @@ std::list DPsim::Utils::findFiles(std::list filennames, return foundnames; } +#ifdef WITH_JSON void DPsim::Utils::applySimulationParametersFromJson(const json config, Simulation &sim) { if (config.contains("timestep")) @@ -451,3 +452,4 @@ void DPsim::Utils::applySynchronousGeneratorParametersFromJson( syngen->applyParametersOperationalPerUnit(); } } +#endif diff --git a/dpsim/src/pybind/Attributes.cpp b/dpsim/src/pybind/Attributes.cpp index a2bf8c1822..8acbc6729f 100644 --- a/dpsim/src/pybind/Attributes.cpp +++ b/dpsim/src/pybind/Attributes.cpp @@ -33,7 +33,9 @@ void addAttributes(py::module_ m) { CPS::AttributeBase>(m, "AttributeReal") .def("get", &CPS::Attribute::get) .def("set", &CPS::Attribute::set) - .def("derive_scaled", &CPS::Attribute::deriveScaled); + .def("derive_scaled", + py::overload_cast( + &CPS::Attribute::template deriveScaled)); py::class_, CPS::AttributePointer>, @@ -48,11 +50,22 @@ void addAttributes(py::module_ m) { CPS::AttributeBase>(m, "AttributeComplex") .def("get", &CPS::Attribute::get) .def("set", &CPS::Attribute::set) - .def("derive_real", &CPS::Attribute::deriveReal) - .def("derive_imag", &CPS::Attribute::deriveImag) - .def("derive_mag", &CPS::Attribute::deriveMag) - .def("derive_phase", &CPS::Attribute::derivePhase) - .def("derive_scaled", &CPS::Attribute::deriveScaled); + .def("derive_real", + py::overload_cast<>( + &CPS::Attribute::template deriveReal<>)) + .def("derive_imag", + py::overload_cast<>( + &CPS::Attribute::template deriveImag<>)) + .def("derive_mag", + py::overload_cast<>( + &CPS::Attribute::template deriveMag<>)) + .def("derive_phase", + py::overload_cast<>( + &CPS::Attribute::template derivePhase<>)) + .def("derive_scaled", + py::overload_cast( + &CPS::Attribute::template deriveScaled< + CPS::Complex>)); py::class_, CPS::AttributePointer>, diff --git a/dpsim/src/pybind/CMakeLists.txt b/dpsim/src/pybind/CMakeLists.txt index 6788950dc2..7e9734b3ca 100644 --- a/dpsim/src/pybind/CMakeLists.txt +++ b/dpsim/src/pybind/CMakeLists.txt @@ -15,4 +15,12 @@ set_target_properties(dpsimpy LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) target_link_libraries(dpsimpy PRIVATE dpsim) -target_include_directories(dpsimpy PUBLIC ${DPSIMPY_INCLUDE_DIRS}) \ No newline at end of file +target_include_directories(dpsimpy PUBLIC ${DPSIMPY_INCLUDE_DIRS}) + +install(TARGETS dpsimpy + EXPORT dpsimpy + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_PYTHON_SITEPACKAGESDIR} +) diff --git a/dpsim/src/pybind/DPComponents.cpp b/dpsim/src/pybind/DPComponents.cpp index 316a91a856..e74ddfabb3 100644 --- a/dpsim/src/pybind/DPComponents.cpp +++ b/dpsim/src/pybind/DPComponents.cpp @@ -155,7 +155,7 @@ void addDPPh1Components(py::module_ mDPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def("set_parameters", &CPS::DP::Ph1::Switch::setParameters, "open_resistance"_a, "closed_resistance"_a, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "closed"_a = false) .def("open", &CPS::DP::Ph1::Switch::open) .def("close", &CPS::DP::Ph1::Switch::close) @@ -169,7 +169,7 @@ void addDPPh1Components(py::module_ mDPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def("set_parameters", &CPS::DP::Ph1::varResSwitch::setParameters, "open_resistance"_a, "closed_resistance"_a, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "closed"_a = false) .def("open", &CPS::DP::Ph1::varResSwitch::open) .def("close", &CPS::DP::Ph1::varResSwitch::close) @@ -363,7 +363,7 @@ void addDPPh1Components(py::module_ mDPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def(py::init(), "uid"_a, "name"_a, "loglevel"_a = CPS::Logger::Level::off, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "with_trafo"_a = false) .def("set_parameters", &CPS::DP::Ph1::AvVoltageSourceInverterDQ::setParameters, @@ -405,9 +405,8 @@ void addDPPh1Components(py::module_ mDPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def(py::init(), "uid"_a, "name"_a, "loglevel"_a = CPS::Logger::Level::off, - // cppcheck-suppress assignBoolToPointer - "with_resistive_losses"_a = - false) + // cppcheck-suppress assignBoolToPointer + "with_resistive_losses"_a = false) .def("set_parameters", py::overload_cast( @@ -481,7 +480,7 @@ void addDPPh3Components(py::module_ mDPPh3) { "loglevel"_a = CPS::Logger::Level::off) .def("set_parameters", &CPS::DP::Ph3::SeriesSwitch::setParameters, "open_resistance"_a, "closed_resistance"_a, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "closed"_a = false) .def("open", &CPS::DP::Ph3::SeriesSwitch::open) .def("close", &CPS::DP::Ph3::SeriesSwitch::close) diff --git a/dpsim/src/pybind/EMTComponents.cpp b/dpsim/src/pybind/EMTComponents.cpp index 52a1b7bbda..2afc272f7d 100644 --- a/dpsim/src/pybind/EMTComponents.cpp +++ b/dpsim/src/pybind/EMTComponents.cpp @@ -14,6 +14,11 @@ #include #include +#ifdef WITH_JSON +#include +using json = nlohmann::json; +#endif + namespace py = pybind11; using namespace pybind11::literals; @@ -114,6 +119,77 @@ void addEMTPh1Components(py::module_ mEMTPh1) { .def("open", &CPS::EMT::Ph1::Switch::open) .def("close", &CPS::EMT::Ph1::Switch::close) .def("connect", &CPS::EMT::Ph1::Switch::connect); + + py::class_, + CPS::SimPowerComp>(mEMTPh1, "Full_Serial_RLC", + py::multiple_inheritance()) + .def(py::init()) + .def(py::init()) + .def("set_parameters", + &CPS::EMT::Ph1::SSN::Full_Serial_RLC::setParameters, "R"_a, "L"_a, + "C"_a) + .def("connect", &CPS::EMT::Ph1::SSN::Full_Serial_RLC::connect) + .def_property("R", createAttributeGetter("R"), + createAttributeSetter("R")) + .def_property("L", createAttributeGetter("L"), + createAttributeSetter("L")) + .def_property("C", createAttributeGetter("C"), + createAttributeSetter("C")); + + py::class_, + CPS::SimPowerComp>(mEMTPh1, "SSNTypeI2T", + py::multiple_inheritance()) + .def(py::init()) + .def(py::init()) + .def("set_parameters", &CPS::EMT::Ph1::SSNTypeI2T::setParameters, "A"_a, + "B"_a, "C"_a, "D"_a) + .def("manual_init", &CPS::EMT::Ph1::SSNTypeI2T::manualInit, + "initialState"_a, "initialInput"_a, "initialOldInput"_a, + "initCurr"_a, "initVol"_a) + .def("connect", &CPS::EMT::Ph1::SSNTypeI2T::connect) + .def_property("mA", createAttributeGetter("mA"), + createAttributeSetter("mA")) + .def_property("mB", createAttributeGetter("mB"), + createAttributeSetter("mB")) + .def_property("mC", createAttributeGetter("mC"), + createAttributeSetter("mC")) + .def_property("mD", createAttributeGetter("mD"), + createAttributeSetter("mD")) + .def_property("mdA", createAttributeGetter("mdA"), + createAttributeSetter("mdA")) + .def_property("mdB", createAttributeGetter("mdB"), + createAttributeSetter("mdB")) + .def_property("mdC", createAttributeGetter("mdC"), + createAttributeSetter("mdC")); + + py::class_, + CPS::SimPowerComp>(mEMTPh1, "SSNTypeV2T", + py::multiple_inheritance()) + .def(py::init()) + .def(py::init()) + .def("set_parameters", &CPS::EMT::Ph1::SSNTypeV2T::setParameters, "A"_a, + "B"_a, "C"_a, "D"_a) + .def("manual_init", &CPS::EMT::Ph1::SSNTypeV2T::manualInit, + "initialState"_a, "initialInput"_a, "initialOldInput"_a, + "initCurr"_a, "initVol"_a) + .def("connect", &CPS::EMT::Ph1::SSNTypeV2T::connect) + .def_property("mA", createAttributeGetter("mA"), + createAttributeSetter("mA")) + .def_property("mB", createAttributeGetter("mB"), + createAttributeSetter("mB")) + .def_property("mC", createAttributeGetter("mC"), + createAttributeSetter("mC")) + .def_property("mD", createAttributeGetter("mD"), + createAttributeSetter("mD")) + .def_property("mdA", createAttributeGetter("mdA"), + createAttributeSetter("mdA")) + .def_property("mdB", createAttributeGetter("mdB"), + createAttributeSetter("mdB")) + .def_property("mdC", createAttributeGetter("mdC"), + createAttributeSetter("mdC")); } void addEMTPh3Components(py::module_ mEMTPh3) { @@ -211,9 +287,13 @@ void addEMTPh3Components(py::module_ mEMTPh3) { "parallel_conductance"_a = zeroMatrix(3)) .def("connect", &CPS::EMT::Ph3::PiLine::connect); - py::class_, CPS::SimPowerComp>(mEMTPh3, "RXLoad", py::multiple_inheritance()) - .def(py::init(), "name"_a, "loglevel"_a = CPS::Logger::Level::off) - .def("set_parameters", &CPS::EMT::Ph3::RXLoad::setParameters, "active_power"_a, "reactive_power"_a, "volt"_a, + py::class_, + CPS::SimPowerComp>(mEMTPh3, "RXLoad", + py::multiple_inheritance()) + .def(py::init(), "name"_a, + "loglevel"_a = CPS::Logger::Level::off) + .def("set_parameters", &CPS::EMT::Ph3::RXLoad::setParameters, + "active_power"_a, "reactive_power"_a, "volt"_a, // cppcheck-suppress assignBoolToPointer "reactance_in_series"_a = false) .def("connect", &CPS::EMT::Ph3::RXLoad::connect); @@ -253,12 +333,14 @@ void addEMTPh3Components(py::module_ mEMTPh3) { "Llkq2"_a, "inertia"_a, "init_active_power"_a, "init_reactive_power"_a, "init_terminal_volt"_a, "init_volt_angle"_a, "init_mech_power"_a) +#ifdef WITH_JSON .def("apply_parameters_from_json", [](std::shared_ptr syngen, const CPS::String json) { DPsim::Utils::applySynchronousGeneratorParametersFromJson( json::parse(json), syngen); }) +#endif .def("set_initial_values", &CPS::EMT::Ph3::SynchronGeneratorDQTrapez::setInitialValues, "init_active_power"_a, "init_reactive_power"_a, @@ -379,12 +461,14 @@ void addEMTPh3Components(py::module_ mEMTPh3) { "Llkq2"_a, "inertia"_a, "init_active_power"_a, "init_reactive_power"_a, "init_terminal_volt"_a, "init_volt_angle"_a, "init_mech_power"_a) +#ifdef WITH_JSON .def("apply_parameters_from_json", [](std::shared_ptr syngen, const CPS::String json) { DPsim::Utils::applySynchronousGeneratorParametersFromJson( json::parse(json), syngen); }) +#endif .def("set_initial_values", &CPS::EMT::Ph3::SynchronGeneratorDQODE::setInitialValues, "init_active_power"_a, "init_reactive_power"_a, @@ -474,10 +558,10 @@ void addEMTPh3Components(py::module_ mEMTPh3) { &CPS::EMT::Ph3::SSN::Full_Serial_RLC::setParameters, "R"_a, "L"_a, "C"_a) .def("connect", &CPS::EMT::Ph3::SSN::Full_Serial_RLC::connect) - .def_property("R", createAttributeGetter("R"), - createAttributeSetter("R")) - .def_property("L", createAttributeGetter("L"), - createAttributeSetter("L")) - .def_property("C", createAttributeGetter("C"), - createAttributeSetter("C")); + .def_property("R", createAttributeGetter("R"), + createAttributeSetter("R")) + .def_property("L", createAttributeGetter("L"), + createAttributeSetter("L")) + .def_property("C", createAttributeGetter("C"), + createAttributeSetter("C")); } diff --git a/dpsim/src/pybind/SPComponents.cpp b/dpsim/src/pybind/SPComponents.cpp index 3b833c1de3..44dd0422c7 100644 --- a/dpsim/src/pybind/SPComponents.cpp +++ b/dpsim/src/pybind/SPComponents.cpp @@ -134,7 +134,7 @@ void addSPPh1Components(py::module_ mSPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def("set_parameters", &CPS::SP::Ph1::Switch::setParameters, "open_resistance"_a, "closed_resistance"_a, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "closed"_a = false) .def("open", &CPS::SP::Ph1::Switch::open) .def("close", &CPS::SP::Ph1::Switch::close) @@ -167,7 +167,7 @@ void addSPPh1Components(py::module_ mSPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def("set_parameters", &CPS::SP::Ph1::varResSwitch::setParameters, "open_resistance"_a, "closed_resistance"_a, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "closed"_a = false) .def("open", &CPS::SP::Ph1::varResSwitch::open) .def("close", &CPS::SP::Ph1::varResSwitch::close) @@ -304,7 +304,7 @@ void addSPPh1Components(py::module_ mSPPh1) { "loglevel"_a = CPS::Logger::Level::off) .def(py::init(), "uid"_a, "name"_a, "loglevel"_a = CPS::Logger::Level::off, - // cppcheck-suppress assignBoolToPointer + // cppcheck-suppress assignBoolToPointer "with_trafo"_a = false) .def("set_parameters", &CPS::SP::Ph1::AvVoltageSourceInverterDQ::setParameters, diff --git a/dpsim/src/pybind/SignalComponents.cpp b/dpsim/src/pybind/SignalComponents.cpp index 01821c9dc6..f66b7035e0 100644 --- a/dpsim/src/pybind/SignalComponents.cpp +++ b/dpsim/src/pybind/SignalComponents.cpp @@ -48,6 +48,18 @@ void addSignalComponents(py::module_ mSignal) { .def("get_line_components", &CPS::Signal::DecouplingLineEMT::getLineComponents); + py::class_, + CPS::SimSignalComp>(mSignal, "DecouplingLineEMT_Ph3", + py::multiple_inheritance()) + .def(py::init()) + .def(py::init()) + .def("set_parameters", &CPS::Signal::DecouplingLineEMT_Ph3::setParameters, + "node_1"_a, "node_2"_a, "resistance"_a, "inductance"_a, + "capacitance"_a) + .def("get_line_components", + &CPS::Signal::DecouplingLineEMT_Ph3::getLineComponents); + py::class_, CPS::SimSignalComp>(mSignal, "Exciter", py::multiple_inheritance()) .def(py::init()) diff --git a/dpsim/src/pybind/main.cpp b/dpsim/src/pybind/main.cpp index 39f3c235b5..e6129e4c9e 100644 --- a/dpsim/src/pybind/main.cpp +++ b/dpsim/src/pybind/main.cpp @@ -37,11 +37,11 @@ using namespace pybind11::literals; PYBIND11_MODULE(dpsimpy, m) { m.doc() = R"pbdoc( - DPsim Python bindings - ----------------------- - The Python bindings provide access to most of the DPsim features implemented in C++. - It is possible to run powerflow, quasi-static, dynamic phasor and electromagnetic transient simulations - and to parameterize all components of the network from Python. + DPsim Python bindings + ----------------------- + The Python bindings provide access to most of the DPsim features implemented in C++. + It is possible to run powerflow, quasi-static, dynamic phasor and electromagnetic transient simulations + and to parameterize all components of the network from Python. )pbdoc"; //Enums @@ -200,8 +200,7 @@ PYBIND11_MODULE(dpsimpy, m) { .def("do_steady_state_init", &DPsim::Simulation::doSteadyStateInit) .def("do_frequency_parallelization", &DPsim::Simulation::doFrequencyParallelization) - .def("do_split_subnets", - &DPsim::Simulation::doSplitSubnets) + .def("do_split_subnets", &DPsim::Simulation::doSplitSubnets) .def("set_tearing_components", &DPsim::Simulation::setTearingComponents) .def("add_event", &DPsim::Simulation::addEvent) .def("set_solver_component_behaviour", @@ -270,7 +269,9 @@ PYBIND11_MODULE(dpsimpy, m) { py::class_>(m, "Interface"); - py::class_>(m, "DataLoggerInterface") + py::class_>(m, + "DataLoggerInterface") .def("log_attribute", py::overload_cast( @@ -284,12 +285,14 @@ PYBIND11_MODULE(dpsimpy, m) { "names"_a, "attr"_a) /// Compatibility method. Might be removed later when the python examples have been fully adapted.; .def("log_attribute", - [](DPsim::DataLoggerInterface &logger, const std::vector &names, - const CPS::String &attr, const CPS::IdentifiedObject &comp) { + [](DPsim::DataLoggerInterface &logger, + const std::vector &names, const CPS::String &attr, + const CPS::IdentifiedObject &comp) { logger.logAttribute(names, comp.attribute(attr)); }); - py::class_>(m, "Logger") + py::class_>(m, "Logger") .def(py::init()) .def_static("set_log_dir", &CPS::Logger::setLogDir) .def_static("get_log_dir", &CPS::Logger::logDir) @@ -320,6 +323,60 @@ PYBIND11_MODULE(dpsimpy, m) { logger.logAttribute(names, comp.attribute(attr)); }); + py::class_>(m, + "RealTimeDataLogger") + + .def(py::init([](py::object filename, DPsim::Real final_time, + DPsim::Real time_step) { + py::object fspath = + py::module_::import("os").attr("fspath")(filename); + std::string s = py::cast(fspath); + std::filesystem::path p(s); + return std::make_shared(p, final_time, + time_step); + }), + "filename"_a, "final_time"_a, "time_step"_a) + + .def(py::init([](py::object filename, std::size_t row_number) { + py::object fspath = + py::module_::import("os").attr("fspath")(filename); + std::string s = py::cast(fspath); + std::filesystem::path p(s); + return std::make_shared(p, row_number); + }), + "filename"_a, "row_number"_a) + + .def("log_attribute", + py::overload_cast( + &DPsim::DataLoggerInterface::logAttribute), + "name"_a, "attr"_a, "max_cols"_a = 0, "max_rows"_a = 0) + + .def("log_attribute", + py::overload_cast &, + CPS::AttributeBase::Ptr>( + &DPsim::DataLoggerInterface::logAttribute), + "names"_a, "attr"_a) + + .def( + "log_attribute", + [](DPsim::RealTimeDataLogger &logger, const CPS::String &name, + const CPS::String &attr, const CPS::IdentifiedObject &comp, + CPS::UInt rowsMax, CPS::UInt colsMax) { + logger.logAttribute(name, comp.attribute(attr), rowsMax, colsMax); + }, + "name"_a, "attr"_a, "comp"_a, "rows_max"_a = 0, "cols_max"_a = 0) + + .def( + "log_attribute", + [](DPsim::RealTimeDataLogger &logger, + const std::vector &names, const CPS::String &attr, + const CPS::IdentifiedObject &comp) { + logger.logAttribute(names, comp.attribute(attr)); + }, + "names"_a, "attr"_a, "comp"_a); + py::class_>( m, "IdentifiedObject") .def("name", &CPS::IdentifiedObject::name) diff --git a/examples/Index.ipynb b/examples/Index.ipynb index 6e61e5522d..37f01409f8 100644 --- a/examples/Index.ipynb +++ b/examples/Index.ipynb @@ -15,8 +15,12 @@ "## Examples\n", "\n", "Welcome to the examples collection of DPsim. These examples are a good way to start using DPsim. \\\n", - "They cover DPsim's feature from [simple circuits](./Notebooks/Circuits/CS_R2CL.ipynb) and to more complex benchmarks models like the [IEEE/WSCC 9-bus system](./Notebooks/Grids/WSCC_9-bus_dyn_switch_python.ipynb). \\\n", - "A good place to start is the [Quickstart Guide](./Notebooks/Quickstart%20Guide.ipynb).\n", + "They cover DPsim's feature from [simple circuits](./Notebooks/Circuits/CS_R2CL.ipynb) and to more complex benchmarks models like the [IEEE/WSCC 9-bus system](./Notebooks/Grids/DP_WSCC9bus_SGTrStab_Switch.ipynb). \\\n", + "A good place to start is the [Quickstart Guide](./Notebooks/Quickstart%20Guide.ipynb). Below you will find a list of representative examples.\n", + " - [Infinite bus system with Fault](./Notebooks/Circuits/DP_SP_SynGenTrStab_SMIB_Fault.ipynb) Shows how to implement the Kundur's SMIB system with a balanced fault from scratch and simulates it using Dynamic Phasors\n", + " - [Three bus system in steady state](./Notebooks/Circuits/DP_SP_SynGenTrStab_3Bus_SteadyState.ipynb) Shows how to implement a power system with multiple buses and generators from scratch and simulates it in dynamic steady state\n", + " - [Dynamic Simulation from CIM model](./Notebooks/Grids/DP_CIGRE_MV_withDG_withLoadStep.ipynb) Demonstrates how to implement a dynamic simulation by importing a grid model defined by the Common Information Model (CIM) specification\n", + " - [Power flow from MATPOWER model](./Notebooks/matpower-case9.ipynb) Demonstrates how to implement a power flow by importing a grid model defined in [MATPOWER](https://matpower.org/)\n", "\n", "## Project Website\n", "\n", diff --git a/examples/Matlab/CalculateError.m b/examples/Matlab/CalculateError.m index c2bc39d53d..41847c03a9 100644 --- a/examples/Matlab/CalculateError.m +++ b/examples/Matlab/CalculateError.m @@ -41,12 +41,12 @@ dt = 0.000050; %% read results from c++ simulation while dt <= 0.011000 - + FileName = FileNameVector(i,1:27); Path = strcat('../../../vsa/Results/LoadChange/DPsim/EMT/VBR/', FileName); Log_SynGen = csvread(Path,1); CurrentVector = Log_SynGen(:,1:4); - + %% Calculate and display error %Cut Current and Voltage vector to get steady state results l=length(CurrentVector); @@ -56,7 +56,7 @@ CurrentVector_LC = -CurrentVector(l_new:2*l_new,2); CurrentReference_reduced = zeros(l,2); - + if l == l_Ref CurrentReference_reduced(:,1) = Results_Reference(:,1); CurrentReference_reduced(:,2) = Results_Reference(:,5); @@ -68,8 +68,8 @@ CurrentReference_reduced(n,2) = Results_Reference(m,5); n = n+1; end -end - +end + %Reference current in Steady state and after load change Reference_SS = CurrentReference_reduced(1:l_new,2); Reference_LC = CurrentReference_reduced(l_new:2*l_new,2); @@ -100,7 +100,7 @@ ErrorVector_VBR(i) = 100*err_LC/Peak_Ref_LC; dtVectorVBR(i) = dt; i = i + 1; - + if dt >= 0.001 dt = dt + 0.001; elseif dt >= 0.0001 @@ -109,9 +109,9 @@ dt = dt + 0.000050; end end - - + + %% Dq Model i = 1; @@ -128,12 +128,12 @@ dt = 0.000050; while dt <= 0.000800 - + FileName = FileNameVector(i,1:26); Path = strcat('../../../vsa/Results/LoadChange/DPsim/EMT/Dq/', FileName); Log_SynGen = csvread(Path,1); CurrentVector = Log_SynGen(:,1:4); - + l=length(CurrentVector); l_new=round(1/3*l); @@ -141,7 +141,7 @@ CurrentVector_LC = CurrentVector(l_new:2*l_new,2); CurrentReference_reduced = zeros(l,2); - + if l == l_Ref CurrentReference_reduced(:,1) = Results_Reference(:,1); CurrentReference_reduced(:,2) = Results_Reference(:,5); @@ -153,8 +153,8 @@ CurrentReference_reduced(n,2) = Results_Reference(m,5); n = n+1; end - end - + end + %Reference current in Steady state and after load change Reference_SS = CurrentReference_reduced(1:l_new,2); Reference_LC = CurrentReference_reduced(l_new:2*l_new,2); @@ -183,7 +183,7 @@ ErrorVector_dq(i) = 100*err_LC/Peak_Ref_LC; dtVectordq(i) = dt; i = i + 1; - + if dt >= 0.0001 dt = dt + 0.0001; else @@ -232,7 +232,7 @@ currentDP(row,col+compOffsetDP)*sin(2*pi*60*currentDP(row,1)); end - + l_DP=length(currentShiftDP); l_new_DP=round(1/3*l_DP); @@ -240,7 +240,7 @@ CurrentVector_LC_DP = -currentShiftDP(l_new_DP:2*l_new_DP,2); CurrentReference_reduced = zeros(l_DP,2); - + if l_DP == l_Ref CurrentReference_reduced(:,1) = Results_Reference(:,1); CurrentReference_reduced(:,2) = Results_Reference(:,5); @@ -252,8 +252,8 @@ CurrentReference_reduced(n,2) = Results_Reference(m,5); n = n+1; end - end - + end + %Reference current in Steady state and after load change Reference_SS = CurrentReference_reduced(1:l_new_DP,2); Reference_LC = CurrentReference_reduced(l_new_DP:2*l_new_DP,2); @@ -282,7 +282,7 @@ ErrorVector_VBRDP(i) = 100*err_LC_DP/Peak_Ref_LC; dtVectorVBRDP(i) = dt; i = i + 1; - + if dt >= 0.001 dt = dt + 0.001; elseif dt >= 0.0001 @@ -315,7 +315,7 @@ Log_SynGen = csvread(Path,1); currentDP = Log_SynGen(:,1:7); compOffsetDP = (size(currentDP,2) - 1) / 2; - + currentShiftDP = currentDP(:,1); col = 2; for row = 1:size(currentDP,1) @@ -323,7 +323,7 @@ currentDP(row,col+compOffsetDP)*sin(2*pi*60*currentDP(row,1)); end - + l_DP=length(currentShiftDP); l_new_DP=round(1/3*l_DP); @@ -331,7 +331,7 @@ CurrentVector_LC_DP = currentShiftDP(l_new_DP:2*l_new_DP,2); CurrentReference_reduced = zeros(l_DP,2); - + if l_DP == l_Ref CurrentReference_reduced(:,1) = Results_Reference(:,1); CurrentReference_reduced(:,2) = Results_Reference(:,5); @@ -343,8 +343,8 @@ CurrentReference_reduced(n,2) = Results_Reference(m,5); n = n+1; end - end - + end + %Reference current in Steady state and after load change Reference_SS = CurrentReference_reduced(1:l_new_DP,2); Reference_LC = CurrentReference_reduced(l_new_DP:2*l_new_DP,2); @@ -372,7 +372,7 @@ ErrorVector_dqDP(i) = 100*err_LC_DP/Peak_Ref_LC; dtVectordqDP(i) = dt; i = i + 1; - + if dt >= 0.0001 dt = dt + 0.0001; else @@ -393,7 +393,7 @@ legend({'EMT VBR','DP VBR'},'FontSize',12) ylabel('Error [%]','FontSize',12); xlabel('Time Step [s]','FontSize',12); - + set(plot1,'LineWidth',2); set(plot2,'LineWidth',2); set(plotp,'LineWidth',2); @@ -413,7 +413,7 @@ ylabel('Error [%]','FontSize',12); xlabel('Time Step [s]','FontSize',12); ylim([0 16]); - + set(plot3,'LineWidth',2); set(plot4,'LineWidth',2); @@ -432,7 +432,7 @@ ylabel('Error [%]','FontSize',12); xlabel('Time Step [s]','FontSize',12); ylim([0 2]); - + set(plot3,'LineWidth',2); set(plot4,'LineWidth',2); diff --git a/examples/Matlab/CompareDPandEMT_DPsim.m b/examples/Matlab/CompareDPandEMT_DPsim.m index b9a4927d56..ddb9b1eb74 100644 --- a/examples/Matlab/CompareDPandEMT_DPsim.m +++ b/examples/Matlab/CompareDPandEMT_DPsim.m @@ -2,7 +2,7 @@ clear %% read PLECS results -Results_PLECSV = csvread('../../vsa/Results/SynGenVBREmt_ABCFault_DPSim/data_synGenVBR_v.csv'); +Results_PLECSV = csvread('../../vsa/Results/SynGenVBREmt_ABCFault_DPSim/data_synGenVBR_v.csv'); Results_PLECSI = csvread('../../vsa/Results/SynGenVBREmt_ABCFault_DPSim/data_synGenVBR_i.csv'); %% Read data from DP simulation and calculate absolute value and phase @@ -125,4 +125,3 @@ legend('Current Phase c PLECS', 'DP shift c', 'DP abs c') xlabel('time [s]') ylabel('current [A]') - diff --git a/examples/Matlab/CompareSynGenResults.m b/examples/Matlab/CompareSynGenResults.m index fc487d4557..aac358ead3 100644 --- a/examples/Matlab/CompareSynGenResults.m +++ b/examples/Matlab/CompareSynGenResults.m @@ -21,8 +21,8 @@ Peak_Ref_SS = max(Results_Reference(1:l_Ref/3,5)); Peak_Ref_LC = max(Results_Reference(l_Ref/3:2*l_Ref/3,5)); if strcmp(TestName,'TestExciterAndTurbine') == 1 -omega_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/omega.csv'); -vt_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/vt.csv'); +omega_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/omega.csv'); +vt_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/vt.csv'); end %% read results from c++ simulation Path = ['../../../vsa/Results/',TestName,'/DPsim/',SimulationType,'/',GeneratorType,'/']; @@ -112,7 +112,7 @@ title('Current phase c'); legend('ic DPSim','ic Simulink'); -if strcmp(TestName,'TestExciterAndTurbine') == 1 +if strcmp(TestName,'TestExciterAndTurbine') == 1 h7=figure(7) hold off plotomega1 = plot(Log_SynGen(:,1),Log_SynGen(:,6)); @@ -167,10 +167,10 @@ CurrentVector_SS = CurrentVector(1:l_new,2); CurrentVector_LC = CurrentVector(l_new:2*l_new,2); end - + CurrentReference_reduced = zeros(l,2); - + if l == l_Ref CurrentReference_reduced(:,1) = Results_Reference(:,1); CurrentReference_reduced(:,2) = Results_Reference(:,5); @@ -182,8 +182,8 @@ CurrentReference_reduced(n,2) = Results_Reference(m,5); n = n+1; end -end - +end + %Reference current in Steady state and after load change Reference_SS = CurrentReference_reduced(1:l_new,2); Reference_LC = CurrentReference_reduced(l_new:2*l_new,2); @@ -214,4 +214,4 @@ %% Calculate avarage step time StepTimeVector = Log_SynGen(:,7); -disp(['Avarage step time for generator: ', num2str(mean(StepTimeVector)*1000), ' ms']); \ No newline at end of file +disp(['Avarage step time for generator: ', num2str(mean(StepTimeVector)*1000), ' ms']); diff --git a/examples/Matlab/CompareVBRandDQ.m b/examples/Matlab/CompareVBRandDQ.m index bfc3ee02e8..38edff1399 100644 --- a/examples/Matlab/CompareVBRandDQ.m +++ b/examples/Matlab/CompareVBRandDQ.m @@ -59,4 +59,4 @@ xlabel('time [s]','FontSize',12) ylabel('current [A]','FontSize',12) -legend({'Reference','EMT Classical','EMT VBR'},'FontSize',12); \ No newline at end of file +legend({'Reference','EMT Classical','EMT VBR'},'FontSize',12); diff --git a/examples/Matlab/CompareVBRandDQ_DP.m b/examples/Matlab/CompareVBRandDQ_DP.m index c2980f98dc..a29c71c565 100644 --- a/examples/Matlab/CompareVBRandDQ_DP.m +++ b/examples/Matlab/CompareVBRandDQ_DP.m @@ -99,9 +99,9 @@ if abs_on == 1 && shift_on == 1 legend({'Reference', 'DP shift VBR', 'DP abs VBR', 'DP shift Classical', 'DP abs Classical'},'FontSize',12) -elseif abs_on == 1 && shift_on == 0 +elseif abs_on == 1 && shift_on == 0 legend({'Reference', 'DP abs VBR', 'DP abs Classical'},'FontSize',12) -elseif abs_on == 0 && shift_on == 1 +elseif abs_on == 0 && shift_on == 1 legend({'Reference', 'DP shift VBR', 'DP shift Classical'},'FontSize',12) end @@ -197,13 +197,11 @@ if abs_on == 1 && shift_on == 1 legend({'Reference', 'DP shift VBR', 'DP abs VBR', 'DP shift Classical', 'DP abs Classical'},'FontSize',12) -elseif abs_on == 1 && shift_on == 0 +elseif abs_on == 1 && shift_on == 0 legend({'Reference', 'DP abs VBR', 'DP abs Classical'},'FontSize',12) -elseif abs_on == 0 && shift_on == 1 +elseif abs_on == 0 && shift_on == 1 legend({'Reference', 'DP shift VBR', 'DP shift Classical'},'FontSize',12) end xlabel('time [s]','FontSize',12) ylabel('current [A]','FontSize',12) - - diff --git a/examples/Matlab/DP_CompareSynGenResults.m b/examples/Matlab/DP_CompareSynGenResults.m index 8c8baa2e4c..ac96a986fe 100644 --- a/examples/Matlab/DP_CompareSynGenResults.m +++ b/examples/Matlab/DP_CompareSynGenResults.m @@ -17,8 +17,8 @@ Results_Reference= csvread(['../../../vsa/Results/',TestName,'/Simulink/Voltages_and_currents.csv']); if strcmp(TestName,'TestExciterAndTurbine') == 1 -omega_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/omega.csv'); -vt_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/vt.csv'); +omega_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/omega.csv'); +vt_Reference = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/vt.csv'); end l_Ref = length(Results_Reference); @@ -138,7 +138,7 @@ if strcmp(GeneratorType,'VBR') == 1 legend({'Reference', 'DP VBR abs'},'FontSize',12) else - legend({'Reference', 'DP Classical abs'},'FontSize',12) + legend({'Reference', 'DP Classical abs'},'FontSize',12) end xlabel('Time [s]','FontSize',12); ylabel('Current [A]','FontSize',12); @@ -199,7 +199,7 @@ set(h7,'pos',[5 5 24 13]) pos = get(h7,'Position'); set(h7,'PaperPositionMode','Auto','PaperUnits','centimeters','PaperSize',[pos(3), pos(4)]) -% +% h8 = figure(8) hold off plotvt1 = plot(Log_SynGen(:,1),Log_SynGen(:,11)); @@ -227,10 +227,10 @@ CurrentVector_LC_DP = -currentShiftDP(l_new_DP:2*l_new_DP,2); else CurrentVector_SS_DP = currentShiftDP(1:l_new_DP,2); - CurrentVector_LC_DP = currentShiftDP(l_new_DP:2*l_new_DP,2); + CurrentVector_LC_DP = currentShiftDP(l_new_DP:2*l_new_DP,2); end CurrentReference_reduced = zeros(l_DP,2); - + if l_DP == l_Ref CurrentReference_reduced(:,1) = Results_Reference(:,1); CurrentReference_reduced(:,2) = Results_Reference(:,5); @@ -242,8 +242,8 @@ CurrentReference_reduced(n,2) = Results_Reference(m,5); n = n+1; end - end - + end + %Reference current in Steady state and after load change Reference_SS = CurrentReference_reduced(1:l_new_DP,2); Reference_LC = CurrentReference_reduced(l_new_DP:2*l_new_DP,2); @@ -269,4 +269,3 @@ disp(['Root Mean-squared error ia ',TestName,': ', num2str(100*err_LC_DP/Peak_Ref_LC), ' %']); disp(' '); disp(' '); - diff --git a/examples/Matlab/ExciterTest.m b/examples/Matlab/ExciterTest.m index 016a2e497f..428e4e8719 100644 --- a/examples/Matlab/ExciterTest.m +++ b/examples/Matlab/ExciterTest.m @@ -2,7 +2,7 @@ %% read Simulink results -Results_Simulink = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/ExciterOutput_Simulink.csv'); +Results_Simulink = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/ExciterOutput_Simulink.csv'); %% read results from c++ simulation Results_DPsim = csvread('../../../vsa/Results/TestExciterAndTurbine/DPsim/EMT/VBR/ExciterOutput_DPSim.csv'); diff --git a/examples/Matlab/FundamentalToStandard.m b/examples/Matlab/FundamentalToStandard.m index 6256d9c221..ccc6022a8f 100644 --- a/examples/Matlab/FundamentalToStandard.m +++ b/examples/Matlab/FundamentalToStandard.m @@ -4,11 +4,11 @@ Laq, L1q, L2q, R1q, R2q) %FundamentalToStandard Transform fundamental machine parameters to standard %parameters -% The calculations are based on the classical definition. +% The calculations are based on the classical definition. % Equations used are from Kundur p. 144 - 147 % ---- Relationship between parameters used in DPSim and parameters -% defined in Kundur: +% defined in Kundur: % Lad = Lmd % L1d = Llkd % Lfd = Llfd @@ -52,4 +52,3 @@ Lq_t = Ll + Laq*L1q/(Laq+L1q); end - diff --git a/examples/Matlab/StandardToFundamental.m b/examples/Matlab/StandardToFundamental.m index 13ef7751c2..fd44adcea9 100644 --- a/examples/Matlab/StandardToFundamental.m +++ b/examples/Matlab/StandardToFundamental.m @@ -18,4 +18,3 @@ R1q = (Laq + L1q)/(Tq0_t*377); R2q = (1/(Tq0_s*377))*(L2q + Laq*L1q/(Laq+L1q)); end - diff --git a/examples/Matlab/TurbineTest.m b/examples/Matlab/TurbineTest.m index 8ca69bb85c..d10e7cc8a9 100644 --- a/examples/Matlab/TurbineTest.m +++ b/examples/Matlab/TurbineTest.m @@ -2,8 +2,8 @@ %% read Simulink results -Results_Simulink = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/TurbineOutput.csv'); -Omega_Simulink = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/omega.csv'); +Results_Simulink = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/TurbineOutput.csv'); +Omega_Simulink = csvread('../../../vsa/Results/TestExciterAndTurbine/Simulink/omega.csv'); %% read results from c++ simulation Results_DPsim = csvread('../../../vsa/Results/TestExciterAndTurbine/DPsim/EMT/VBR/TurbineOutput_DPsim.csv'); diff --git a/examples/Matlab/compareDpAndEmt.m b/examples/Matlab/compareDpAndEmt.m index 0f51bf706b..d4ba286db1 100644 --- a/examples/Matlab/compareDpAndEmt.m +++ b/examples/Matlab/compareDpAndEmt.m @@ -30,7 +30,7 @@ % Downsampling of reference voltage for row = 1:size(voltageShiftDP,1) if voltageRef(size(voltageRef,1),1) >= voltageShiftDP(row,1) - indices(row) = find(voltageRef(:,1) == voltageShiftDP(row,1),1); + indices(row) = find(voltageRef(:,1) == voltageShiftDP(row,1),1); end end for i = 1:size(indices,2) @@ -61,4 +61,3 @@ ylabel('voltage [V]') end - diff --git a/examples/Matlab/compareDpAndEmtInterp.m b/examples/Matlab/compareDpAndEmtInterp.m index afb3177f53..faff0f9648 100644 --- a/examples/Matlab/compareDpAndEmtInterp.m +++ b/examples/Matlab/compareDpAndEmtInterp.m @@ -60,4 +60,3 @@ ylabel('voltage [V]') end - diff --git a/examples/Matlab/compareDpResults.m b/examples/Matlab/compareDpResults.m index 5f182231d0..664597fdbd 100644 --- a/examples/Matlab/compareDpResults.m +++ b/examples/Matlab/compareDpResults.m @@ -59,4 +59,4 @@ xlabel('time [s]') ylabel('voltage [V]') -end \ No newline at end of file +end diff --git a/examples/Matlab/mmi_ICCEP.m b/examples/Matlab/mmi_ICCEP.m index 677af4b5f9..6b3d56573d 100644 --- a/examples/Matlab/mmi_ICCEP.m +++ b/examples/Matlab/mmi_ICCEP.m @@ -97,4 +97,4 @@ [mseDPInterp, mseEMTInterp] = compareDpAndEmtInterp(filenameRef, filenameVoltageDP, filenameVoltageEMT, 3); comparison(10,:) = [40 mseEMT(4) mseEMTInterp(4) mseDP(4) mseDPInterp(4)] -dlmwrite('comparison_table.csv',comparison,';') \ No newline at end of file +dlmwrite('comparison_table.csv',comparison,';') diff --git a/examples/Matlab/plotDpEmtVoltage.m b/examples/Matlab/plotDpEmtVoltage.m index 3760f2bea1..d5e08ecddc 100644 --- a/examples/Matlab/plotDpEmtVoltage.m +++ b/examples/Matlab/plotDpEmtVoltage.m @@ -42,4 +42,4 @@ xlabel('time [s]') ylabel('voltage [V]') -end \ No newline at end of file +end diff --git a/examples/Notebooks/Circuits/CS_R2CL print_attributes.ipynb b/examples/Notebooks/Circuits/CS_R2CL print_attributes.ipynb index 7727043782..ed5222c411 100644 --- a/examples/Notebooks/Circuits/CS_R2CL print_attributes.ipynb +++ b/examples/Notebooks/Circuits/CS_R2CL print_attributes.ipynb @@ -34,24 +34,24 @@ "# DPsim EMT simulation\n", "import dpsimpy\n", "\n", - "name = 'EMT_CS_R2CL'\n", + "name = \"EMT_CS_R2CL\"\n", "\n", "# Nodes\n", "gnd = dpsimpy.emt.SimNode.gnd\n", - "n1 = dpsimpy.emt.SimNode('n1')\n", - "n2 = dpsimpy.emt.SimNode('n2')\n", + "n1 = dpsimpy.emt.SimNode(\"n1\")\n", + "n2 = dpsimpy.emt.SimNode(\"n2\")\n", "\n", "# Components\n", - "cs = dpsimpy.emt.ph1.CurrentSource('cs')\n", + "cs = dpsimpy.emt.ph1.CurrentSource(\"cs\")\n", "cs.I_ref = complex(10, 0)\n", "cs.f_src = 50\n", - "r1 = dpsimpy.emt.ph1.Resistor('r_1')\n", + "r1 = dpsimpy.emt.ph1.Resistor(\"r_1\")\n", "r1.R = 1\n", - "c1 = dpsimpy.emt.ph1.Capacitor('c_1')\n", + "c1 = dpsimpy.emt.ph1.Capacitor(\"c_1\")\n", "c1.C = 0.001\n", - "l1 = dpsimpy.emt.ph1.Inductor('l_1')\n", + "l1 = dpsimpy.emt.ph1.Inductor(\"l_1\")\n", "l1.L = 0.001\n", - "r2 = dpsimpy.emt.ph1.Resistor('r_2')\n", + "r2 = dpsimpy.emt.ph1.Resistor(\"r_2\")\n", "r2.R = 1\n", "\n", "cs.print_attribute_list()\n", @@ -60,9 +60,9 @@ "l1.print_attribute_list()\n", "r2.print_attribute_list()\n", "\n", - "cs.print_attribute('v_intf')\n", - "cs.print_attribute('right_vector')\n", - "l1.print_attribute('L')\n", + "cs.print_attribute(\"v_intf\")\n", + "cs.print_attribute(\"right_vector\")\n", + "l1.print_attribute(\"L\")\n", "\n", "# Connections\n", "cs.connect([gnd, n1])\n", @@ -76,10 +76,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(name)\n", - "logger.log_attribute('n1.v', 'v', n1)\n", - "logger.log_attribute('n2.v', 'v', n2)\n", - "logger.log_attribute('cs.i_intf', 'i_intf', cs)\n", - "logger.log_attribute('c_1.i_intf', 'i_intf', c1)\n", + "logger.log_attribute(\"n1.v\", \"v\", n1)\n", + "logger.log_attribute(\"n2.v\", \"v\", n2)\n", + "logger.log_attribute(\"cs.i_intf\", \"i_intf\", cs)\n", + "logger.log_attribute(\"c_1.i_intf\", \"i_intf\", c1)\n", "\n", "sim = dpsimpy.Simulation(name)\n", "sim.set_domain(dpsimpy.Domain.EMT)\n", @@ -105,9 +105,9 @@ "source": [ "sim.run()\n", "print(cs)\n", - "cs.print_attribute('v_intf')\n", - "cs.print_attribute('right_vector')\n", - "l1.print_attribute('L')" + "cs.print_attribute(\"v_intf\")\n", + "cs.print_attribute(\"right_vector\")\n", + "l1.print_attribute(\"L\")" ] }, { @@ -117,11 +117,11 @@ "outputs": [], "source": [ "# read EMT results\n", - "work_dir = 'logs/'\n", - "log_name = 'EMT_CS_R2CL'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/\"\n", + "log_name = \"EMT_CS_R2CL\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_emt = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "ts_dpsim_emt = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -130,15 +130,15 @@ "metadata": {}, "outputs": [], "source": [ - "v1_emt = 'n1.v'\n", - "v2_emt = 'n2.v'\n", - "i01_emt = 'cs.i_intf'\n", - "i12_emt = 'c_1.i_intf'\n", + "v1_emt = \"n1.v\"\n", + "v2_emt = \"n2.v\"\n", + "i01_emt = \"cs.i_intf\"\n", + "i12_emt = \"c_1.i_intf\"\n", "\n", - "ts_dpsim_emt[v1_emt].label = 'v1 EMT'\n", - "ts_dpsim_emt[v2_emt].label = 'v2 EMT'\n", - "ts_dpsim_emt[i01_emt].label = 'i01 EMT'\n", - "ts_dpsim_emt[i12_emt].label = 'i12 EMT'\n", + "ts_dpsim_emt[v1_emt].label = \"v1 EMT\"\n", + "ts_dpsim_emt[v2_emt].label = \"v2 EMT\"\n", + "ts_dpsim_emt[i01_emt].label = \"i01 EMT\"\n", + "ts_dpsim_emt[i12_emt].label = \"i12 EMT\"\n", "pt.plot_timeseries(1, ts_dpsim_emt[v1_emt])\n", "pt.plot_timeseries(1, ts_dpsim_emt[v2_emt])\n", "pt.plot_timeseries(2, ts_dpsim_emt[i01_emt])\n", @@ -161,23 +161,23 @@ "# DPsim DP simulation\n", "import dpsimpy\n", "\n", - "name = 'DP_CS_R2CL'\n", + "name = \"DP_CS_R2CL\"\n", "\n", "# Nodes\n", "gnd = dpsimpy.dp.SimNode.gnd\n", - "n1 = dpsimpy.dp.SimNode('n1')\n", - "n2 = dpsimpy.dp.SimNode('n2')\n", + "n1 = dpsimpy.dp.SimNode(\"n1\")\n", + "n2 = dpsimpy.dp.SimNode(\"n2\")\n", "\n", "# Components\n", - "cs = dpsimpy.dp.ph1.CurrentSource('cs')\n", - "cs.I_ref = complex(10,0)\n", - "r1 = dpsimpy.dp.ph1.Resistor('r_1')\n", + "cs = dpsimpy.dp.ph1.CurrentSource(\"cs\")\n", + "cs.I_ref = complex(10, 0)\n", + "r1 = dpsimpy.dp.ph1.Resistor(\"r_1\")\n", "r1.R = 1\n", - "c1 = dpsimpy.dp.ph1.Capacitor('c_1')\n", + "c1 = dpsimpy.dp.ph1.Capacitor(\"c_1\")\n", "c1.C = 0.001\n", - "l1 = dpsimpy.dp.ph1.Inductor('l_1')\n", + "l1 = dpsimpy.dp.ph1.Inductor(\"l_1\")\n", "l1.L = 0.001\n", - "r2 = dpsimpy.dp.ph1.Resistor('r_2')\n", + "r2 = dpsimpy.dp.ph1.Resistor(\"r_2\")\n", "r2.R = 1\n", "\n", "print(cs)\n", @@ -194,14 +194,14 @@ "r2.connect([n2, gnd])\n", "\n", "# Define system topology\n", - "system = dpsimpy.SystemTopology(50, [gnd, n1, n2], [cs, r1, c1, l1, r2]);\n", + "system = dpsimpy.SystemTopology(50, [gnd, n1, n2], [cs, r1, c1, l1, r2])\n", "\n", "# Logging\n", "logger = dpsimpy.Logger(name)\n", - "logger.log_attribute('n1.v', 'v', n1)\n", - "logger.log_attribute('n2.v', 'v', n2)\n", - "logger.log_attribute('cs.i_intf', 'i_intf', cs)\n", - "logger.log_attribute('c_1.i_intf', 'i_intf', c1)\n", + "logger.log_attribute(\"n1.v\", \"v\", n1)\n", + "logger.log_attribute(\"n2.v\", \"v\", n2)\n", + "logger.log_attribute(\"cs.i_intf\", \"i_intf\", cs)\n", + "logger.log_attribute(\"c_1.i_intf\", \"i_intf\", c1)\n", "\n", "sim = dpsimpy.Simulation(name)\n", "sim.set_system(system)\n", @@ -235,13 +235,13 @@ "outputs": [], "source": [ "# read DP results\n", - "work_dir = 'logs/'\n", - "log_name = 'DP_CS_R2CL'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/\"\n", + "log_name = \"DP_CS_R2CL\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "\n", - "#convert to emt\n", + "# convert to emt\n", "ts_dpsim_dp_emt = ts.frequency_shift_list(ts_dpsim_dp, 50)" ] }, @@ -251,15 +251,15 @@ "metadata": {}, "outputs": [], "source": [ - "v1_dp = 'n1.v_shift'\n", - "v2_dp = 'n2.v_shift'\n", - "i01_dp = 'cs.i_intf_shift'\n", - "i12_dp = 'c_1.i_intf_shift'\n", + "v1_dp = \"n1.v_shift\"\n", + "v2_dp = \"n2.v_shift\"\n", + "i01_dp = \"cs.i_intf_shift\"\n", + "i12_dp = \"c_1.i_intf_shift\"\n", "\n", - "ts_dpsim_dp_emt[v1_dp].label = 'v1 DP'\n", - "ts_dpsim_dp_emt[v2_dp].label = 'v2 DP'\n", - "ts_dpsim_dp_emt[i01_dp].label = 'i01 DP'\n", - "ts_dpsim_dp_emt[i12_dp].label = 'i12 DP'\n", + "ts_dpsim_dp_emt[v1_dp].label = \"v1 DP\"\n", + "ts_dpsim_dp_emt[v2_dp].label = \"v2 DP\"\n", + "ts_dpsim_dp_emt[i01_dp].label = \"i01 DP\"\n", + "ts_dpsim_dp_emt[i12_dp].label = \"i12 DP\"\n", "pt.plot_timeseries(1, ts_dpsim_dp_emt[v1_dp])\n", "pt.plot_timeseries(1, ts_dpsim_dp_emt[v2_dp])\n", "pt.plot_timeseries(2, ts_dpsim_dp_emt[i01_dp])\n", @@ -288,4 +288,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/examples/Notebooks/Circuits/CS_R2CL.ipynb b/examples/Notebooks/Circuits/CS_R2CL.ipynb index 70fc1173f3..e6ecccadb6 100644 --- a/examples/Notebooks/Circuits/CS_R2CL.ipynb +++ b/examples/Notebooks/Circuits/CS_R2CL.ipynb @@ -16,10 +16,10 @@ "import villas.dataprocessing.readtools as rt\n", "import villas.dataprocessing.plottools as pt\n", "from villas.dataprocessing.timeseries import TimeSeries as ts\n", - "import math \n", + "import math\n", "import dpsimpy\n", "\n", - "#%matplotlib widget\n" + "# %matplotlib widget" ] }, { @@ -36,28 +36,28 @@ "outputs": [], "source": [ "# DPsim EMT simulation\n", - "name = 'EMT_CS_R2CL'\n", + "name = \"EMT_CS_R2CL\"\n", "\n", "# Nodes\n", "gnd = dpsimpy.emt.SimNode.gnd\n", - "n1 = dpsimpy.emt.SimNode('n1')\n", - "n2 = dpsimpy.emt.SimNode('n2')\n", + "n1 = dpsimpy.emt.SimNode(\"n1\")\n", + "n2 = dpsimpy.emt.SimNode(\"n2\")\n", "\n", "# initialize node voltages as in modelica\n", "n1.set_initial_voltage(complex(6.26676, -2.13813) * math.sqrt(3))\n", "n2.set_initial_voltage(complex(-0.539123, 0.42205) * math.sqrt(3))\n", "\n", "# Components\n", - "cs = dpsimpy.emt.ph1.CurrentSource('cs')\n", + "cs = dpsimpy.emt.ph1.CurrentSource(\"cs\")\n", "cs.I_ref = complex(10, 0)\n", "cs.f_src = 50\n", - "r1 = dpsimpy.emt.ph1.Resistor('r_1', dpsimpy.LogLevel.off)\n", + "r1 = dpsimpy.emt.ph1.Resistor(\"r_1\", dpsimpy.LogLevel.off)\n", "r1.R = 1\n", - "c1 = dpsimpy.emt.ph1.Capacitor('c_1', dpsimpy.LogLevel.off)\n", + "c1 = dpsimpy.emt.ph1.Capacitor(\"c_1\", dpsimpy.LogLevel.off)\n", "c1.C = 0.001\n", - "l1 = dpsimpy.emt.ph1.Inductor('l_1', dpsimpy.LogLevel.off)\n", + "l1 = dpsimpy.emt.ph1.Inductor(\"l_1\", dpsimpy.LogLevel.off)\n", "l1.L = 0.001\n", - "r2 = dpsimpy.emt.ph1.Resistor('r_2')\n", + "r2 = dpsimpy.emt.ph1.Resistor(\"r_2\")\n", "r2.R = 1\n", "\n", "# Connections\n", @@ -72,11 +72,11 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(name)\n", - "logger.log_attribute('n1.v', 'v', n1)\n", - "logger.log_attribute('n2.v', 'v', n2)\n", - "logger.log_attribute('cs.i_intf', 'i_intf', cs)\n", - "logger.log_attribute('c_1.i_intf', 'i_intf', c1)\n", - "logger.log_attribute('l_1.i_intf', 'i_intf', l1)\n", + "logger.log_attribute(\"n1.v\", \"v\", n1)\n", + "logger.log_attribute(\"n2.v\", \"v\", n2)\n", + "logger.log_attribute(\"cs.i_intf\", \"i_intf\", cs)\n", + "logger.log_attribute(\"c_1.i_intf\", \"i_intf\", c1)\n", + "logger.log_attribute(\"l_1.i_intf\", \"i_intf\", l1)\n", "\n", "sim = dpsimpy.Simulation(name)\n", "sim.set_domain(dpsimpy.Domain.EMT)\n", @@ -110,11 +110,11 @@ "outputs": [], "source": [ "# read EMT results\n", - "work_dir = 'logs/'\n", - "log_name = 'EMT_CS_R2CL'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/\"\n", + "log_name = \"EMT_CS_R2CL\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_emt = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "ts_dpsim_emt = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -123,15 +123,15 @@ "metadata": {}, "outputs": [], "source": [ - "v1_emt = 'n1.v'\n", - "v2_emt = 'n2.v'\n", - "ic1_emt = 'c_1.i_intf'\n", - "il1_emt = 'l_1.i_intf'\n", + "v1_emt = \"n1.v\"\n", + "v2_emt = \"n2.v\"\n", + "ic1_emt = \"c_1.i_intf\"\n", + "il1_emt = \"l_1.i_intf\"\n", "\n", - "ts_dpsim_emt[v1_emt].label = 'v1 EMT'\n", - "ts_dpsim_emt[v2_emt].label = 'v2 EMT'\n", - "ts_dpsim_emt[ic1_emt].label = 'ic1 EMT'\n", - "ts_dpsim_emt[il1_emt].label = 'il1 EMT'\n", + "ts_dpsim_emt[v1_emt].label = \"v1 EMT\"\n", + "ts_dpsim_emt[v2_emt].label = \"v2 EMT\"\n", + "ts_dpsim_emt[ic1_emt].label = \"ic1 EMT\"\n", + "ts_dpsim_emt[il1_emt].label = \"il1 EMT\"\n", "pt.plot_timeseries(1, ts_dpsim_emt[v1_emt])\n", "pt.plot_timeseries(1, ts_dpsim_emt[v2_emt])\n", "pt.plot_timeseries(2, ts_dpsim_emt[ic1_emt])\n", @@ -152,27 +152,27 @@ "outputs": [], "source": [ "# DPsim DP simulation\n", - "name = 'DP_CS_R2CL'\n", + "name = \"DP_CS_R2CL\"\n", "\n", "# Nodes\n", "gnd = dpsimpy.dp.SimNode.gnd\n", - "n1 = dpsimpy.dp.SimNode('n1')\n", - "n2 = dpsimpy.dp.SimNode('n2')\n", + "n1 = dpsimpy.dp.SimNode(\"n1\")\n", + "n2 = dpsimpy.dp.SimNode(\"n2\")\n", "\n", "# initialize node voltages as in simulunk\n", "n1.set_initial_voltage(complex(6.26676, -2.13813) * math.sqrt(2))\n", "n2.set_initial_voltage(complex(-0.539123, 0.42205) * math.sqrt(2))\n", "\n", "# Components\n", - "cs = dpsimpy.dp.ph1.CurrentSource('cs')\n", - "cs.I_ref = complex(10,0)\n", - "r1 = dpsimpy.dp.ph1.Resistor('r_1')\n", + "cs = dpsimpy.dp.ph1.CurrentSource(\"cs\")\n", + "cs.I_ref = complex(10, 0)\n", + "r1 = dpsimpy.dp.ph1.Resistor(\"r_1\")\n", "r1.R = 1\n", - "c1 = dpsimpy.dp.ph1.Capacitor('c_1')\n", + "c1 = dpsimpy.dp.ph1.Capacitor(\"c_1\")\n", "c1.C = 0.001\n", - "l1 = dpsimpy.dp.ph1.Inductor('l_1')\n", + "l1 = dpsimpy.dp.ph1.Inductor(\"l_1\")\n", "l1.L = 0.001\n", - "r2 = dpsimpy.dp.ph1.Resistor('r_2')\n", + "r2 = dpsimpy.dp.ph1.Resistor(\"r_2\")\n", "r2.R = 1\n", "\n", "# Connections\n", @@ -187,11 +187,11 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(name)\n", - "logger.log_attribute('n1.v', 'v', n1)\n", - "logger.log_attribute('n2.v', 'v', n2)\n", - "logger.log_attribute('cs.i_intf', 'i_intf', cs)\n", - "logger.log_attribute('c_1.i_intf', 'i_intf', c1)\n", - "logger.log_attribute('l_1.i_intf', 'i_intf', l1)\n", + "logger.log_attribute(\"n1.v\", \"v\", n1)\n", + "logger.log_attribute(\"n2.v\", \"v\", n2)\n", + "logger.log_attribute(\"cs.i_intf\", \"i_intf\", cs)\n", + "logger.log_attribute(\"c_1.i_intf\", \"i_intf\", c1)\n", + "logger.log_attribute(\"l_1.i_intf\", \"i_intf\", l1)\n", "\n", "sim = dpsimpy.Simulation(name)\n", "sim.set_system(system)\n", @@ -225,13 +225,13 @@ "outputs": [], "source": [ "# read DP results\n", - "work_dir = 'logs/'\n", - "log_name = 'DP_CS_R2CL'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/\"\n", + "log_name = \"DP_CS_R2CL\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "\n", - "#convert to emt\n", + "# convert to emt\n", "ts_dpsim_dp_emt = ts.frequency_shift_list(ts_dpsim_dp, 50)" ] }, @@ -241,15 +241,15 @@ "metadata": {}, "outputs": [], "source": [ - "v1_dp = 'n1.v_shift'\n", - "v2_dp = 'n2.v_shift'\n", - "ic1_dp = 'c_1.i_intf_shift'\n", - "il1_dp = 'l_1.i_intf_shift'\n", + "v1_dp = \"n1.v_shift\"\n", + "v2_dp = \"n2.v_shift\"\n", + "ic1_dp = \"c_1.i_intf_shift\"\n", + "il1_dp = \"l_1.i_intf_shift\"\n", "\n", - "ts_dpsim_dp_emt[v1_dp].label = 'v1 DP'\n", - "ts_dpsim_dp_emt[v2_dp].label = 'v2 DP'\n", - "ts_dpsim_dp_emt[ic1_dp].label = 'ic1 DP'\n", - "ts_dpsim_dp_emt[il1_dp].label = 'il1 DP'\n", + "ts_dpsim_dp_emt[v1_dp].label = \"v1 DP\"\n", + "ts_dpsim_dp_emt[v2_dp].label = \"v2 DP\"\n", + "ts_dpsim_dp_emt[ic1_dp].label = \"ic1 DP\"\n", + "ts_dpsim_dp_emt[il1_dp].label = \"il1 DP\"\n", "pt.plot_timeseries(1, ts_dpsim_dp_emt[v1_dp])\n", "pt.plot_timeseries(1, ts_dpsim_dp_emt[v2_dp])\n", "pt.plot_timeseries(2, ts_dpsim_dp_emt[ic1_dp])\n", @@ -274,12 +274,12 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/62d774a31d40663368487e2751f93ed3ee53139d/Modelica/BasicGrids/CS_R2CL_Modelica.csv'\n", - "local_file = 'reference-results/CS_R2CL_Modelica.csv'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/62d774a31d40663368487e2751f93ed3ee53139d/Modelica/BasicGrids/CS_R2CL_Modelica.csv\"\n", + "local_file = \"reference-results/CS_R2CL_Modelica.csv\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", "ts_mod = rt.read_timeseries_simulink(local_file)" ] @@ -290,15 +290,15 @@ "metadata": {}, "outputs": [], "source": [ - "v1_mod = 'capacitor.v1'\n", - "v2_mod = 'capacitor.v2'\n", - "ic1_mod = 'capacitor.i'\n", - "il1_mod = 'inductor.i'\n", + "v1_mod = \"capacitor.v1\"\n", + "v2_mod = \"capacitor.v2\"\n", + "ic1_mod = \"capacitor.i\"\n", + "il1_mod = \"inductor.i\"\n", "\n", - "ts_mod[v1_mod].label = 'v1 Mod'\n", - "ts_mod[v2_mod].label = 'v2 Mod'\n", - "ts_mod[ic1_mod].label = 'ic1 Mod'\n", - "ts_mod[il1_mod].label = 'il1 Mod'\n", + "ts_mod[v1_mod].label = \"v1 Mod\"\n", + "ts_mod[v2_mod].label = \"v2 Mod\"\n", + "ts_mod[ic1_mod].label = \"ic1 Mod\"\n", + "ts_mod[il1_mod].label = \"il1 Mod\"\n", "pt.plot_timeseries(1, ts_mod[v1_mod])\n", "pt.plot_timeseries(1, ts_mod[v2_mod])\n", "pt.plot_timeseries(2, ts_mod[ic1_mod])\n", @@ -318,13 +318,13 @@ "metadata": {}, "outputs": [], "source": [ - "v1_emt = 'n1.v'\n", - "v2_emt = 'n2.v'\n", + "v1_emt = \"n1.v\"\n", + "v2_emt = \"n2.v\"\n", "\n", "# plot v1\n", "pt.plot_timeseries(1, ts_dpsim_emt[v1_emt])\n", "pt.plot_timeseries(1, ts_dpsim_dp_emt[v1_dp])\n", - "pt.plot_timeseries(1, ts_dpsim_dp['n1.v'].abs())\n", + "pt.plot_timeseries(1, ts_dpsim_dp[\"n1.v\"].abs())\n", "pt.plot_timeseries(1, ts_mod[v1_mod])\n", "# plot v2\n", "pt.plot_timeseries(2, ts_dpsim_emt[v2_emt])\n", diff --git a/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_PCM_LoadStep.ipynb b/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_PCM_LoadStep.ipynb index 878c3c61f1..f9e55507ff 100644 --- a/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_PCM_LoadStep.ipynb +++ b/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_PCM_LoadStep.ipynb @@ -33,7 +33,7 @@ "import matplotlib.pyplot as plt\n", "import dpsimpy\n", "\n", - "#%matplotlib widget" + "# %matplotlib widget" ] }, { @@ -50,13 +50,18 @@ "metadata": {}, "outputs": [], "source": [ - "root_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = root_path + '/build/dpsim/examples/cxx/'\n", + "root_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = root_path + \"/build/dpsim/examples/cxx/\"\n", "\n", - "name_executable_vbr = 'DP_SMIB_ReducedOrderSG_LoadStep'\n", + "name_executable_vbr = \"DP_SMIB_ReducedOrderSG_LoadStep\"\n", "name_vbr = \"DP_SMIB_ReducedOrderSG_VBR_LoadStep\"\n", "\n", - "name_executable_pcm = 'DP_SMIB_ReducedOrderSGIterative_LoadStep'\n", + "name_executable_pcm = \"DP_SMIB_ReducedOrderSGIterative_LoadStep\"\n", "name_pcm = \"DP_SMIB_ReducedOrderSGIterativePCM_LoadStep\"\n", "\n", "# times in s\n", @@ -71,14 +76,14 @@ "max_iter = 10\n", "tolerance = 1e-6\n", "\n", - "roi_begin_idx = int(roi_begin/timestep_pcm)\n", - "roi_end_idx = int(roi_end/timestep_pcm)\n", + "roi_begin_idx = int(roi_begin / timestep_pcm)\n", + "roi_end_idx = int(roi_end / timestep_pcm)\n", "\n", - "logs_path = 'logs'\n", + "logs_path = \"logs\"\n", "if not os.path.exists(logs_path):\n", " os.mkdir(logs_path)\n", - " \n", - "var_name = 'SynGen.Te'\n", + "\n", + "var_name = \"SynGen.Te\"\n", "\n", "te_ref = 0.5454986888690558" ] @@ -102,14 +107,14 @@ "### Power System\n", "nominal_voltage_hv = 230e3\n", "nominal_voltage_mv = 24e3\n", - "ratio = nominal_voltage_mv/nominal_voltage_hv\n", + "ratio = nominal_voltage_mv / nominal_voltage_hv\n", "frequency = 60\n", "omega = 2 * pi * frequency\n", "\n", "### Generator\n", "nom_power = 555e6\n", "set_point_active_power = 300e6\n", - "set_point_voltage = 1.05*nominal_voltage_mv\n", + "set_point_voltage = 1.05 * nominal_voltage_mv\n", "H = 3.7\n", "Td0_t = 8.0669\n", "Td0_s = 0.0300\n", @@ -125,16 +130,16 @@ "Lq = 1.7600\n", "L0 = 0.15\n", "Taa = 0\n", - " \n", + "\n", "### PiLine parameters calculated from CIGRE Benchmark system\n", "line_length = 100\n", - "line_resistance = 1.27e-4 * 529 * line_length * pow(ratio,2)\n", - "line_inductance = 9.05e-4 * 529 / omega * line_length * pow(ratio,2)\n", - "line_capacitance = (1.81e-3 / 529) / omega * line_length / pow(ratio,2)\n", + "line_resistance = 1.27e-4 * 529 * line_length * pow(ratio, 2)\n", + "line_inductance = 9.05e-4 * 529 / omega * line_length * pow(ratio, 2)\n", + "line_capacitance = (1.81e-3 / 529) / omega * line_length / pow(ratio, 2)\n", "line_conductance = 0.0048\n", "\n", "### Load step\n", - "load_step_activePower = 100e6; " + "load_step_activePower = 100e6;" ] }, { @@ -156,16 +161,20 @@ "\n", "### Nodes\n", "gnd_pf = dpsimpy.sp.SimNode.gnd\n", - "n1_pf = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single)\n", - "n2_pf = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + "n1_pf = dpsimpy.sp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + "n2_pf = dpsimpy.sp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", "### Components\n", "\n", "# syncrhon generator\n", - "gen_pf = dpsimpy.sp.ph1.SynchronGenerator('gen', dpsimpy.LogLevel.debug)\n", - "gen_pf.set_parameters(rated_apparent_power=nom_power, rated_voltage=nominal_voltage_mv, \n", - " set_point_active_power=set_point_active_power, set_point_voltage=set_point_voltage, \n", - " powerflow_bus_type=dpsimpy.PowerflowBusType.PV)\n", + "gen_pf = dpsimpy.sp.ph1.SynchronGenerator(\"gen\", dpsimpy.LogLevel.debug)\n", + "gen_pf.set_parameters(\n", + " rated_apparent_power=nom_power,\n", + " rated_voltage=nominal_voltage_mv,\n", + " set_point_active_power=set_point_active_power,\n", + " set_point_voltage=set_point_voltage,\n", + " powerflow_bus_type=dpsimpy.PowerflowBusType.PV,\n", + ")\n", "gen_pf.set_base_voltage(nominal_voltage_mv)\n", "gen_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PV)\n", "\n", @@ -176,8 +185,10 @@ "extnet_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "\n", "# PiLine\n", - "pi_line_pf = dpsimpy.sp.ph1.PiLine('Pi_Line_pf', dpsimpy.LogLevel.debug)\n", - "pi_line_pf.set_parameters(R=line_resistance, L=line_inductance, C=line_capacitance, G=line_conductance)\n", + "pi_line_pf = dpsimpy.sp.ph1.PiLine(\"Pi_Line_pf\", dpsimpy.LogLevel.debug)\n", + "pi_line_pf.set_parameters(\n", + " R=line_resistance, L=line_inductance, C=line_capacitance, G=line_conductance\n", + ")\n", "pi_line_pf.set_base_voltage(nominal_voltage_mv)\n", "\n", "### Connections\n", @@ -186,14 +197,16 @@ "extnet_pf.connect([n2_pf])\n", "\n", "### Define system topology\n", - "system_pf = dpsimpy.SystemTopology(frequency, [n1_pf, n2_pf], [gen_pf, pi_line_pf, extnet_pf])\n", + "system_pf = dpsimpy.SystemTopology(\n", + " frequency, [n1_pf, n2_pf], [gen_pf, pi_line_pf, extnet_pf]\n", + ")\n", "\n", "# Logging\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", - "logger_pf.log_attribute('n1.v', 'v', n1_pf)\n", - "logger_pf.log_attribute('n2.v', 'v', n2_pf)\n", - "logger_pf.log_attribute('p_inj', 'p_inj', extnet_pf)\n", - "logger_pf.log_attribute('q_inj', 'q_inj', extnet_pf)\n", + "logger_pf.log_attribute(\"n1.v\", \"v\", n1_pf)\n", + "logger_pf.log_attribute(\"n2.v\", \"v\", n2_pf)\n", + "logger_pf.log_attribute(\"p_inj\", \"p_inj\", extnet_pf)\n", + "logger_pf.log_attribute(\"q_inj\", \"q_inj\", extnet_pf)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -220,83 +233,157 @@ "metadata": {}, "outputs": [], "source": [ - "def dp_reducedOrderSG_loadStep(sim_pf, gen_pf, gen_model=\"4TPM\", event_time=0.1, final_time=0.5, time_step=10e-6, max_iter=10, tolerance=1e-6):\n", - " \n", + "def dp_reducedOrderSG_loadStep(\n", + " sim_pf,\n", + " gen_pf,\n", + " gen_model=\"4TPM\",\n", + " event_time=0.1,\n", + " final_time=0.5,\n", + " time_step=10e-6,\n", + " max_iter=10,\n", + " tolerance=1e-6,\n", + "):\n", " ### DPsim DP simulation\n", " name = \"DP_SMIB_ReducedOrderSGIterative_LoadStep_\" + gen_model\n", " dpsimpy.Logger.set_log_dir(\"logs/\" + name)\n", "\n", " ### Nodes\n", " gnd = dpsimpy.dp.SimNode.gnd\n", - " n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single) \n", - " n2 = dpsimpy.dp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + " n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + " n2 = dpsimpy.dp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", " ### Components\n", "\n", " # syncrhon generator\n", " gen = None\n", - " if (gen_model==\"4VBR\"):\n", - " gen = dpsimpy.dp.ph1.SynchronGenerator4OrderVBR('gen', dpsimpy.LogLevel.debug)\n", - " gen.set_operational_parameters_per_unit(nom_power=nom_power, nom_voltage=nominal_voltage_mv, nom_frequency=frequency, \n", - " H=H, Ld=Ld, Lq=Lq, L0=L0, Ld_t=Ld_t, Lq_t=Lq_t, Td0_t=Td0_t, Tq0_t=Tq0_t)\t\t\n", - " elif (gen_model==\"6VBR\"):\n", - " gen = dpsimpy.dp.ph1.SynchronGenerator6bOrderVBR('gen', dpsimpy.LogLevel.debug)\n", - " gen.set_operational_parameters_per_unit(nom_power=nom_power, nom_voltage=nominal_voltage_mv, nom_frequency=frequency, \n", - " H=H, Ld=Ld, Lq=Lq, L0=L0, Ld_t=Ld_t, Lq_t=Lq_t, Td0_t=Td0_t, Tq0_t=Tq0_t,\n", - " Ld_s=Ld_s, Lq_s=Lq_s, Td0_s=Td0_s, Tq0_s=Tq0_s)\n", - " elif (gen_model==\"4TPM\"):\n", - " gen = dpsimpy.dp.ph1.SynchronGenerator4OrderTPM('gen', dpsimpy.LogLevel.debug)\n", - " gen.set_operational_parameters_per_unit(nom_power=nom_power, nom_voltage=nominal_voltage_mv, nom_frequency=frequency, \n", - " H=H, Ld=Ld, Lq=Lq, L0=L0, Ld_t=Ld_t, Lq_t=Lq_t, Td0_t=Td0_t, Tq0_t=Tq0_t)\n", + " if gen_model == \"4VBR\":\n", + " gen = dpsimpy.dp.ph1.SynchronGenerator4OrderVBR(\"gen\", dpsimpy.LogLevel.debug)\n", + " gen.set_operational_parameters_per_unit(\n", + " nom_power=nom_power,\n", + " nom_voltage=nominal_voltage_mv,\n", + " nom_frequency=frequency,\n", + " H=H,\n", + " Ld=Ld,\n", + " Lq=Lq,\n", + " L0=L0,\n", + " Ld_t=Ld_t,\n", + " Lq_t=Lq_t,\n", + " Td0_t=Td0_t,\n", + " Tq0_t=Tq0_t,\n", + " )\n", + " elif gen_model == \"6VBR\":\n", + " gen = dpsimpy.dp.ph1.SynchronGenerator6bOrderVBR(\"gen\", dpsimpy.LogLevel.debug)\n", + " gen.set_operational_parameters_per_unit(\n", + " nom_power=nom_power,\n", + " nom_voltage=nominal_voltage_mv,\n", + " nom_frequency=frequency,\n", + " H=H,\n", + " Ld=Ld,\n", + " Lq=Lq,\n", + " L0=L0,\n", + " Ld_t=Ld_t,\n", + " Lq_t=Lq_t,\n", + " Td0_t=Td0_t,\n", + " Tq0_t=Tq0_t,\n", + " Ld_s=Ld_s,\n", + " Lq_s=Lq_s,\n", + " Td0_s=Td0_s,\n", + " Tq0_s=Tq0_s,\n", + " )\n", + " elif gen_model == \"4TPM\":\n", + " gen = dpsimpy.dp.ph1.SynchronGenerator4OrderTPM(\"gen\", dpsimpy.LogLevel.debug)\n", + " gen.set_operational_parameters_per_unit(\n", + " nom_power=nom_power,\n", + " nom_voltage=nominal_voltage_mv,\n", + " nom_frequency=frequency,\n", + " H=H,\n", + " Ld=Ld,\n", + " Lq=Lq,\n", + " L0=L0,\n", + " Ld_t=Ld_t,\n", + " Lq_t=Lq_t,\n", + " Td0_t=Td0_t,\n", + " Tq0_t=Tq0_t,\n", + " )\n", " gen.set_max_iterations(max_iter=max_iter)\n", " gen.set_tolerance(tolerance=tolerance)\n", - " elif (gen_model==\"4PCM\"):\n", - " gen = dpsimpy.dp.ph1.SynchronGenerator4OrderPCM('gen', dpsimpy.LogLevel.debug)\n", - " gen.set_operational_parameters_per_unit(nom_power=nom_power, nom_voltage=nominal_voltage_mv, nom_frequency=frequency, \n", - " H=H, Ld=Ld, Lq=Lq, L0=L0, Ld_t=Ld_t, Lq_t=Lq_t, Td0_t=Td0_t, Tq0_t=Tq0_t)\n", + " elif gen_model == \"4PCM\":\n", + " gen = dpsimpy.dp.ph1.SynchronGenerator4OrderPCM(\"gen\", dpsimpy.LogLevel.debug)\n", + " gen.set_operational_parameters_per_unit(\n", + " nom_power=nom_power,\n", + " nom_voltage=nominal_voltage_mv,\n", + " nom_frequency=frequency,\n", + " H=H,\n", + " Ld=Ld,\n", + " Lq=Lq,\n", + " L0=L0,\n", + " Ld_t=Ld_t,\n", + " Lq_t=Lq_t,\n", + " Td0_t=Td0_t,\n", + " Tq0_t=Tq0_t,\n", + " )\n", " gen.set_max_iterations(max_iter=max_iter)\n", - " gen.set_tolerance(tolerance=tolerance)\t\t\n", - " elif (gen_model==\"6PCM\"):\n", - " gen = dpsimpy.dp.ph1.SynchronGenerator6OrderPCM('gen', dpsimpy.LogLevel.debug)\n", - " gen.set_operational_parameters_per_unit(nom_power=nom_power, nom_voltage=nominal_voltage_mv, nom_frequency=frequency, \n", - " H=H, Ld=Ld, Lq=Lq, L0=L0, Ld_t=Ld_t, Lq_t=Lq_t, Td0_t=Td0_t, Tq0_t=Tq0_t,\n", - " Ld_s=Ld_s, Lq_s=Lq_s, Td0_s=Td0_s, Tq0_s=Tq0_s)\n", + " gen.set_tolerance(tolerance=tolerance)\n", + " elif gen_model == \"6PCM\":\n", + " gen = dpsimpy.dp.ph1.SynchronGenerator6OrderPCM(\"gen\", dpsimpy.LogLevel.debug)\n", + " gen.set_operational_parameters_per_unit(\n", + " nom_power=nom_power,\n", + " nom_voltage=nominal_voltage_mv,\n", + " nom_frequency=frequency,\n", + " H=H,\n", + " Ld=Ld,\n", + " Lq=Lq,\n", + " L0=L0,\n", + " Ld_t=Ld_t,\n", + " Lq_t=Lq_t,\n", + " Td0_t=Td0_t,\n", + " Tq0_t=Tq0_t,\n", + " Ld_s=Ld_s,\n", + " Lq_s=Lq_s,\n", + " Td0_s=Td0_s,\n", + " Tq0_s=Tq0_s,\n", + " )\n", " gen.set_max_iterations(max_iter=max_iter)\n", " gen.set_tolerance(tolerance=tolerance)\n", "\n", " # Switch\n", - " switch = dpsimpy.dp.ph1.Switch('Load_Add_Switch_', dpsimpy.LogLevel.debug)\n", - " resistance = abs(sim_pf.get_idobj_attr(n1_pf.name(), 'v').get()[0][0])**2 / load_step_activePower\n", + " switch = dpsimpy.dp.ph1.Switch(\"Load_Add_Switch_\", dpsimpy.LogLevel.debug)\n", + " resistance = (\n", + " abs(sim_pf.get_idobj_attr(n1_pf.name(), \"v\").get()[0][0]) ** 2\n", + " / load_step_activePower\n", + " )\n", " switch.set_parameters(1e9, resistance)\n", " switch.open()\n", "\n", " # pi line\n", - " pi_line = dpsimpy.dp.ph1.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", - " pi_line.set_parameters(series_resistance=line_resistance,\n", - " series_inductance=line_inductance,\n", - " parallel_capacitance=line_capacitance,\n", - " parallel_conductance=line_conductance)\n", + " pi_line = dpsimpy.dp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", + " pi_line.set_parameters(\n", + " series_resistance=line_resistance,\n", + " series_inductance=line_inductance,\n", + " parallel_capacitance=line_capacitance,\n", + " parallel_conductance=line_conductance,\n", + " )\n", "\n", " # Slack\n", - " slack = dpsimpy.dp.ph1.NetworkInjection('slack', dpsimpy.LogLevel.debug)\n", + " slack = dpsimpy.dp.ph1.NetworkInjection(\"slack\", dpsimpy.LogLevel.debug)\n", " slack.set_parameters(V_ref=nominal_voltage_mv)\n", - " \n", + "\n", " ### Connections\n", " gen.connect([n1])\n", " switch.connect([gnd, n1])\n", " pi_line.connect([n1, n2])\n", " slack.connect([n2])\n", - " \n", + "\n", " ### Define system topology\n", " system = dpsimpy.SystemTopology(frequency, [n1, n2], [gen, pi_line, slack, switch])\n", "\n", " ### Logging\n", " logger = dpsimpy.Logger(name)\n", - " logger.log_attribute('Te', 'Te', gen)\n", + " logger.log_attribute(\"Te\", \"Te\", gen)\n", "\n", " # init node voltages and SG power with power flow\n", " system.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", - " \n", + "\n", " ### Simulation\n", " sim = dpsimpy.Simulation(name, dpsimpy.LogLevel.debug)\n", " sim.set_system(system)\n", @@ -304,15 +391,15 @@ " sim.set_domain(dpsimpy.Domain.DP)\n", " sim.set_time_step(time_step)\n", " sim.set_final_time(final_time)\n", - " if (gen_model==\"4VBR\" or gen_model==\"6VBR\"):\n", + " if gen_model == \"4VBR\" or gen_model == \"6VBR\":\n", " sim.do_system_matrix_recomputation(True)\n", - " \n", + "\n", " sw_event_1 = dpsimpy.event.SwitchEvent(event_time, switch, True)\n", " sim.add_event(sw_event_1)\n", - " \n", + "\n", " sim.add_logger(logger)\n", " sim.run()\n", - " \n", + "\n", " return name" ] }, @@ -338,7 +425,14 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = dp_reducedOrderSG_loadStep(sim_pf, gen_pf, gen_model=\"4VBR\", event_time=load_step_time, final_time=end_time, time_step=timestep_vbr)" + "log_name = dp_reducedOrderSG_loadStep(\n", + " sim_pf,\n", + " gen_pf,\n", + " gen_model=\"4VBR\",\n", + " event_time=load_step_time,\n", + " final_time=end_time,\n", + " time_step=timestep_vbr,\n", + ")" ] }, { @@ -351,9 +445,17 @@ "\n", "file_path = os.getcwd() + \"/logs/\" + log_name + \"/\" + log_name + \".csv\"\n", "ts_dpsim_4VBR = read_timeseries_dpsim(file_path)\n", - "ts_dpsim_4VBR['Te'] = TimeSeries('Te', ts_dpsim_4VBR['Te'].interpolate(timestep_pcm).time, ts_dpsim_4VBR['Te'].interpolate(timestep_pcm).values)\n", - "ts_dpsim_4VBR_roi={}\n", - "ts_dpsim_4VBR_roi['Te'] = TimeSeries('Te', ts_dpsim_4VBR['Te'].time[roi_begin_idx:roi_end_idx], ts_dpsim_4VBR['Te'].values[roi_begin_idx:roi_end_idx])" + "ts_dpsim_4VBR[\"Te\"] = TimeSeries(\n", + " \"Te\",\n", + " ts_dpsim_4VBR[\"Te\"].interpolate(timestep_pcm).time,\n", + " ts_dpsim_4VBR[\"Te\"].interpolate(timestep_pcm).values,\n", + ")\n", + "ts_dpsim_4VBR_roi = {}\n", + "ts_dpsim_4VBR_roi[\"Te\"] = TimeSeries(\n", + " \"Te\",\n", + " ts_dpsim_4VBR[\"Te\"].time[roi_begin_idx:roi_end_idx],\n", + " ts_dpsim_4VBR[\"Te\"].values[roi_begin_idx:roi_end_idx],\n", + ")" ] }, { @@ -370,7 +472,14 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = dp_reducedOrderSG_loadStep(sim_pf, gen_pf, gen_model=\"6VBR\", event_time=load_step_time, final_time=end_time, time_step=timestep_vbr)" + "log_name = dp_reducedOrderSG_loadStep(\n", + " sim_pf,\n", + " gen_pf,\n", + " gen_model=\"6VBR\",\n", + " event_time=load_step_time,\n", + " final_time=end_time,\n", + " time_step=timestep_vbr,\n", + ")" ] }, { @@ -383,9 +492,17 @@ "\n", "file_path = os.getcwd() + \"/logs/\" + log_name + \"/\" + log_name + \".csv\"\n", "ts_dpsim_6VBR = read_timeseries_dpsim(file_path)\n", - "ts_dpsim_6VBR['Te'] = TimeSeries('Te', ts_dpsim_6VBR['Te'].interpolate(timestep_pcm).time, ts_dpsim_6VBR['Te'].interpolate(timestep_pcm).values)\n", - "ts_dpsim_6VBR_roi={}\n", - "ts_dpsim_6VBR_roi['Te'] = TimeSeries('Te', ts_dpsim_6VBR['Te'].time[roi_begin_idx:roi_end_idx], ts_dpsim_6VBR['Te'].values[roi_begin_idx:roi_end_idx])" + "ts_dpsim_6VBR[\"Te\"] = TimeSeries(\n", + " \"Te\",\n", + " ts_dpsim_6VBR[\"Te\"].interpolate(timestep_pcm).time,\n", + " ts_dpsim_6VBR[\"Te\"].interpolate(timestep_pcm).values,\n", + ")\n", + "ts_dpsim_6VBR_roi = {}\n", + "ts_dpsim_6VBR_roi[\"Te\"] = TimeSeries(\n", + " \"Te\",\n", + " ts_dpsim_6VBR[\"Te\"].time[roi_begin_idx:roi_end_idx],\n", + " ts_dpsim_6VBR[\"Te\"].values[roi_begin_idx:roi_end_idx],\n", + ")" ] }, { @@ -402,7 +519,16 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = dp_reducedOrderSG_loadStep(sim_pf, gen_pf, gen_model=\"4PCM\", event_time=load_step_time, final_time=end_time, time_step=timestep_pcm, max_iter=max_iter, tolerance=tolerance)" + "log_name = dp_reducedOrderSG_loadStep(\n", + " sim_pf,\n", + " gen_pf,\n", + " gen_model=\"4PCM\",\n", + " event_time=load_step_time,\n", + " final_time=end_time,\n", + " time_step=timestep_pcm,\n", + " max_iter=max_iter,\n", + " tolerance=tolerance,\n", + ")" ] }, { @@ -415,8 +541,12 @@ "\n", "file_path = os.getcwd() + \"/logs/\" + log_name + \"/\" + log_name + \".csv\"\n", "ts_dpsim_4PCM = read_timeseries_dpsim(file_path)\n", - "ts_dpsim_4PCM_roi={}\n", - "ts_dpsim_4PCM_roi['Te'] = TimeSeries('Te', ts_dpsim_4PCM['Te'].time[roi_begin_idx:roi_end_idx], ts_dpsim_4PCM['Te'].values[roi_begin_idx:roi_end_idx])" + "ts_dpsim_4PCM_roi = {}\n", + "ts_dpsim_4PCM_roi[\"Te\"] = TimeSeries(\n", + " \"Te\",\n", + " ts_dpsim_4PCM[\"Te\"].time[roi_begin_idx:roi_end_idx],\n", + " ts_dpsim_4PCM[\"Te\"].values[roi_begin_idx:roi_end_idx],\n", + ")" ] }, { @@ -433,7 +563,16 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = dp_reducedOrderSG_loadStep(sim_pf, gen_pf, gen_model=\"6PCM\", event_time=load_step_time, final_time=end_time, time_step=timestep_pcm, max_iter=max_iter, tolerance=tolerance)" + "log_name = dp_reducedOrderSG_loadStep(\n", + " sim_pf,\n", + " gen_pf,\n", + " gen_model=\"6PCM\",\n", + " event_time=load_step_time,\n", + " final_time=end_time,\n", + " time_step=timestep_pcm,\n", + " max_iter=max_iter,\n", + " tolerance=tolerance,\n", + ")" ] }, { @@ -445,8 +584,12 @@ "# read Simulink log file\n", "file_path = os.getcwd() + \"/logs/\" + log_name + \"/\" + log_name + \".csv\"\n", "ts_dpsim_6PCM = read_timeseries_dpsim(file_path)\n", - "ts_dpsim_6PCM_roi={}\n", - "ts_dpsim_6PCM_roi['Te'] = TimeSeries('Te', ts_dpsim_6PCM['Te'].time[roi_begin_idx:roi_end_idx], ts_dpsim_6PCM['Te'].values[roi_begin_idx:roi_end_idx])" + "ts_dpsim_6PCM_roi = {}\n", + "ts_dpsim_6PCM_roi[\"Te\"] = TimeSeries(\n", + " \"Te\",\n", + " ts_dpsim_6PCM[\"Te\"].time[roi_begin_idx:roi_end_idx],\n", + " ts_dpsim_6PCM[\"Te\"].values[roi_begin_idx:roi_end_idx],\n", + ")" ] }, { @@ -472,8 +615,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_dpsim_4VBR['Te'].time, ts_dpsim_4VBR['Te'].values, label='VBR')\n", - "plt.plot(ts_dpsim_4PCM['Te'].time, ts_dpsim_4PCM['Te'].values, linestyle='--', label='4 Order PCM - MaxIter 10')\n", + "plt.plot(ts_dpsim_4VBR[\"Te\"].time, ts_dpsim_4VBR[\"Te\"].values, label=\"VBR\")\n", + "plt.plot(\n", + " ts_dpsim_4PCM[\"Te\"].time,\n", + " ts_dpsim_4PCM[\"Te\"].values,\n", + " linestyle=\"--\",\n", + " label=\"4 Order PCM - MaxIter 10\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -484,9 +632,13 @@ "metadata": {}, "outputs": [], "source": [ - "rmse = ts_dpsim_4VBR_roi['Te'].rmse(ts_dpsim_4PCM_roi['Te'], ts_dpsim_4VBR_roi['Te'])/te_ref*100\n", - "print('RMSE of PCM 4 Order = {}%'.format(rmse))\n", - "assert(rmse<0.449)" + "rmse = (\n", + " ts_dpsim_4VBR_roi[\"Te\"].rmse(ts_dpsim_4PCM_roi[\"Te\"], ts_dpsim_4VBR_roi[\"Te\"])\n", + " / te_ref\n", + " * 100\n", + ")\n", + "print(\"RMSE of PCM 4 Order = {}%\".format(rmse))\n", + "assert rmse < 0.449" ] }, { @@ -504,8 +656,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_dpsim_6VBR['Te'].time, ts_dpsim_6VBR['Te'].values, label='6 Order VBR')\n", - "plt.plot(ts_dpsim_6PCM['Te'].time, ts_dpsim_6PCM['Te'].values, linestyle='--', label='6 Order PCM - MaxIter 10')\n", + "plt.plot(ts_dpsim_6VBR[\"Te\"].time, ts_dpsim_6VBR[\"Te\"].values, label=\"6 Order VBR\")\n", + "plt.plot(\n", + " ts_dpsim_6PCM[\"Te\"].time,\n", + " ts_dpsim_6PCM[\"Te\"].values,\n", + " linestyle=\"--\",\n", + " label=\"6 Order PCM - MaxIter 10\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -516,9 +673,13 @@ "metadata": {}, "outputs": [], "source": [ - "rmse = ts_dpsim_6VBR_roi['Te'].rmse(ts_dpsim_6PCM_roi['Te'], ts_dpsim_6VBR_roi['Te'])/te_ref*100\n", - "print('RMSE of PCM 6 Order = {}%'.format(rmse))\n", - "assert(rmse<0.381)" + "rmse = (\n", + " ts_dpsim_6VBR_roi[\"Te\"].rmse(ts_dpsim_6PCM_roi[\"Te\"], ts_dpsim_6VBR_roi[\"Te\"])\n", + " / te_ref\n", + " * 100\n", + ")\n", + "print(\"RMSE of PCM 6 Order = {}%\".format(rmse))\n", + "assert rmse < 0.381" ] }, { diff --git a/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_TPM_LoadStep.ipynb b/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_TPM_LoadStep.ipynb index 8b698f4583..0c05a17f1a 100644 --- a/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_TPM_LoadStep.ipynb +++ b/examples/Notebooks/Circuits/Compare_DP_SMIB_ReducedOrderSG_VBR_TPM_LoadStep.ipynb @@ -32,7 +32,7 @@ "from villas.dataprocessing.timeseries import *\n", "import matplotlib.pyplot as plt\n", "\n", - "#%matplotlib widget" + "# %matplotlib widget" ] }, { @@ -49,13 +49,18 @@ "metadata": {}, "outputs": [], "source": [ - "root_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = root_path + '/build/dpsim/examples/cxx/'\n", + "root_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = root_path + \"/build/dpsim/examples/cxx/\"\n", "\n", - "name_executable_vbr = 'DP_SMIB_ReducedOrderSG_LoadStep'\n", + "name_executable_vbr = \"DP_SMIB_ReducedOrderSG_LoadStep\"\n", "name_vbr = \"DP_SMIB_ReducedOrderSG_VBR_LoadStep\"\n", "\n", - "name_executable_tpm = 'DP_SMIB_ReducedOrderSGIterative_LoadStep'\n", + "name_executable_tpm = \"DP_SMIB_ReducedOrderSGIterative_LoadStep\"\n", "name_tpm = \"DP_SMIB_ReducedOrderSGIterative_LoadStep\"\n", "\n", "# times in s\n", @@ -67,19 +72,19 @@ "# tpm config params\n", "max_iter_array = [0, 1, 2, 5, 10, 20]\n", "tolerance = 1e-10\n", - "sg_model = '4TPM'\n", + "sg_model = \"4TPM\"\n", "\n", "\n", - "roi_begin_idx = int(roi_begin/timestep)\n", - "roi_end_idx = int(roi_end/timestep)\n", + "roi_begin_idx = int(roi_begin / timestep)\n", + "roi_end_idx = int(roi_end / timestep)\n", "\n", - "timestep_str = '{:1.6f}'.format(timestep)\n", + "timestep_str = \"{:1.6f}\".format(timestep)\n", "\n", - "logs_path = 'logs'\n", + "logs_path = \"logs\"\n", "if not os.path.exists(logs_path):\n", " os.mkdir(logs_path)\n", - " \n", - "var_name = 'SynGen.Te'\n", + "\n", + "var_name = \"SynGen.Te\"\n", "\n", "te_ref = 0.5454986888690558" ] @@ -99,15 +104,19 @@ "outputs": [], "source": [ "options_list_vbr = []\n", - "options_list_vbr.append('loadStepEventTime=' + str(load_step_time))\n", - "options_list_vbr.append('TimeStep=' + timestep_str)\n", - "options_list_vbr.append('SimName=' + name_vbr)\n", + "options_list_vbr.append(\"loadStepEventTime=\" + str(load_step_time))\n", + "options_list_vbr.append(\"TimeStep=\" + timestep_str)\n", + "options_list_vbr.append(\"SimName=\" + name_vbr)\n", "\n", "args_options_list_vbr = []\n", "for option in options_list_vbr:\n", - " args_options_list_vbr.extend(['--option', option])\n", + " args_options_list_vbr.extend([\"--option\", option])\n", "\n", - "simVBR = subprocess.Popen([path_exec + name_executable_vbr] + args_options_list_vbr, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "simVBR = subprocess.Popen(\n", + " [path_exec + name_executable_vbr] + args_options_list_vbr,\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(simVBR.communicate()[0].decode())" ] }, @@ -119,7 +128,11 @@ "source": [ "results_path_vbr = logs_path + \"/\" + name_vbr + \"/\" + name_vbr + \".csv\"\n", "ts_vbr = read_timeseries_dpsim(results_path_vbr)[var_name]\n", - "ts_vbr_roi = TimeSeries(ts_vbr.name+'roi',ts_vbr.time[roi_begin_idx:roi_end_idx],ts_vbr.values[roi_begin_idx:roi_end_idx])" + "ts_vbr_roi = TimeSeries(\n", + " ts_vbr.name + \"roi\",\n", + " ts_vbr.time[roi_begin_idx:roi_end_idx],\n", + " ts_vbr.values[roi_begin_idx:roi_end_idx],\n", + ")" ] }, { @@ -137,18 +150,29 @@ "outputs": [], "source": [ "options_list_tpm = []\n", - "options_list_tpm.append('loadStepEventTime=' + str(load_step_time))\n", - "options_list_tpm.append('TimeStep=' + timestep_str)\n", - "options_list_tpm.append('Tolerance=' + str(tolerance))\n", - "options_list_tpm.append('SGModel=' + str(sg_model)) \n", + "options_list_tpm.append(\"loadStepEventTime=\" + str(load_step_time))\n", + "options_list_tpm.append(\"TimeStep=\" + timestep_str)\n", + "options_list_tpm.append(\"Tolerance=\" + str(tolerance))\n", + "options_list_tpm.append(\"SGModel=\" + str(sg_model))\n", "\n", "args_options_list_tpm = []\n", "for option in options_list_tpm:\n", - " args_options_list_tpm.extend(['--option', option])\n", + " args_options_list_tpm.extend([\"--option\", option])\n", "\n", "for max_iter in max_iter_array:\n", - " name_iter = name_tpm + '_MaxIter' + str(max_iter)\n", - " simTPM = subprocess.Popen([path_exec + name_executable_tpm, '--option', 'SimName=' + name_iter, '--option', 'MaxIter=' + str(max_iter)] + args_options_list_tpm, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + " name_iter = name_tpm + \"_MaxIter\" + str(max_iter)\n", + " simTPM = subprocess.Popen(\n", + " [\n", + " path_exec + name_executable_tpm,\n", + " \"--option\",\n", + " \"SimName=\" + name_iter,\n", + " \"--option\",\n", + " \"MaxIter=\" + str(max_iter),\n", + " ]\n", + " + args_options_list_tpm,\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + " )\n", " print(simTPM.communicate()[0].decode())" ] }, @@ -163,10 +187,16 @@ "ts_tpm = []\n", "ts_tpm_roi = []\n", "for max_iter in max_iter_array:\n", - " name_iter = name_tpm + '_MaxIter' + str(max_iter)\n", + " name_iter = name_tpm + \"_MaxIter\" + str(max_iter)\n", " results_path_iter = logs_path + \"/\" + name_iter + \"/\" + name_iter + \".csv\"\n", " ts_tpm.append(read_timeseries_dpsim(results_path_iter)[var_name])\n", - " ts_tpm_roi.append(TimeSeries(ts_tpm[-1].name+'roi',ts_tpm[-1].time[roi_begin_idx:roi_end_idx],ts_tpm[-1].values[roi_begin_idx:roi_end_idx]))" + " ts_tpm_roi.append(\n", + " TimeSeries(\n", + " ts_tpm[-1].name + \"roi\",\n", + " ts_tpm[-1].time[roi_begin_idx:roi_end_idx],\n", + " ts_tpm[-1].values[roi_begin_idx:roi_end_idx],\n", + " )\n", + " )" ] }, { @@ -192,11 +222,16 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_vbr.time, ts_vbr.values, label='VBR')\n", + "plt.plot(ts_vbr.time, ts_vbr.values, label=\"VBR\")\n", "\n", "for max_iter in max_iter_array:\n", " max_iter_idx = max_iter_array.index(max_iter)\n", - " plt.plot(ts_tpm[max_iter_idx].time, ts_tpm[max_iter_idx].values, linestyle='--', label='TPM - MaxIter' + str(max_iter))\n", + " plt.plot(\n", + " ts_tpm[max_iter_idx].time,\n", + " ts_tpm[max_iter_idx].values,\n", + " linestyle=\"--\",\n", + " label=\"TPM - MaxIter\" + str(max_iter),\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -217,11 +252,16 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_vbr_roi.time, ts_vbr_roi.values, label='VBR')\n", + "plt.plot(ts_vbr_roi.time, ts_vbr_roi.values, label=\"VBR\")\n", "\n", "for max_iter in max_iter_array:\n", " max_iter_idx = max_iter_array.index(max_iter)\n", - " plt.plot(ts_tpm_roi[max_iter_idx].time, ts_tpm_roi[max_iter_idx].values, linestyle='--', label='TPM - MaxIter' + str(max_iter))\n", + " plt.plot(\n", + " ts_tpm_roi[max_iter_idx].time,\n", + " ts_tpm_roi[max_iter_idx].values,\n", + " linestyle=\"--\",\n", + " label=\"TPM - MaxIter\" + str(max_iter),\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -244,8 +284,10 @@ "rmse_list = []\n", "for max_iter in max_iter_array:\n", " max_iter_idx = max_iter_array.index(max_iter)\n", - " rmse_list.append(ts_vbr_roi.rmse(ts_tpm_roi[max_iter_idx], ts_vbr_roi)/te_ref*100)\n", - " print('RMSE of TPM with MaxIter={}: {}%'.format(max_iter,rmse_list[-1]))" + " rmse_list.append(\n", + " ts_vbr_roi.rmse(ts_tpm_roi[max_iter_idx], ts_vbr_roi) / te_ref * 100\n", + " )\n", + " print(\"RMSE of TPM with MaxIter={}: {}%\".format(max_iter, rmse_list[-1]))" ] }, { @@ -262,12 +304,12 @@ "metadata": {}, "outputs": [], "source": [ - "assert(rmse_list[0]<0.32)\n", - "assert(rmse_list[1]<0.54)\n", - "assert(rmse_list[2]<0.31)\n", - "assert(rmse_list[3]<0.07)\n", - "assert(rmse_list[4]<0.003)\n", - "assert(rmse_list[5]<2.4e-5)" + "assert rmse_list[0] < 0.32\n", + "assert rmse_list[1] < 0.54\n", + "assert rmse_list[2] < 0.31\n", + "assert rmse_list[3] < 0.07\n", + "assert rmse_list[4] < 0.003\n", + "assert rmse_list[5] < 2.4e-5" ] } ], diff --git a/examples/Notebooks/Circuits/Compare_EMT_DP_Slack_PiLine_PQLoad.ipynb b/examples/Notebooks/Circuits/Compare_EMT_DP_Slack_PiLine_PQLoad.ipynb index 61ecca2b9b..546fa81c99 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_DP_Slack_PiLine_PQLoad.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_DP_Slack_PiLine_PQLoad.ipynb @@ -40,23 +40,23 @@ "# POWERFLOW FOR INITIALIZATION\n", "time_step_pf = final_time\n", "final_time_pf = final_time + time_step_pf\n", - "sim_name_pf = 'EMT_Slack_PiLine_PQLoad_with_PF_Init_PF'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "sim_name_pf = \"EMT_Slack_PiLine_PQLoad_with_PF_Init_PF\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "\n", "# Components\n", - "n1_pf = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single)\n", - "n2_pf = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + "n1_pf = dpsimpy.sp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + "n2_pf = dpsimpy.sp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", - "extnet_pf = dpsimpy.sp.ph1.NetworkInjection('Slack', dpsimpy.LogLevel.debug)\n", + "extnet_pf = dpsimpy.sp.ph1.NetworkInjection(\"Slack\", dpsimpy.LogLevel.debug)\n", "extnet_pf.set_parameters(voltage_set_point=V_nom)\n", "extnet_pf.set_base_voltage(V_nom)\n", "extnet_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "\n", - "line_pf = dpsimpy.sp.ph1.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", + "line_pf = dpsimpy.sp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", "line_pf.set_parameters(R=line_resistance, L=line_inductance, C=line_capacitance)\n", "line_pf.set_base_voltage(V_nom)\n", "\n", - "load_pf = dpsimpy.sp.ph1.Shunt('Load', dpsimpy.LogLevel.debug)\n", + "load_pf = dpsimpy.sp.ph1.Shunt(\"Load\", dpsimpy.LogLevel.debug)\n", "load_pf.set_parameters(G=p_load_nom / (V_nom**2), B=-q_load_nom / (V_nom**2))\n", "load_pf.set_base_voltage(V_nom)\n", "\n", @@ -68,9 +68,9 @@ "\n", "# Logging\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", - "logger_pf.log_attribute('v1', 'v', n1_pf)\n", - "logger_pf.log_attribute('v2', 'v', n2_pf)\n", - "logger_pf.log_attribute('i12', 'i_intf', line_pf)\n", + "logger_pf.log_attribute(\"v1\", \"v\", n1_pf)\n", + "logger_pf.log_attribute(\"v2\", \"v\", n2_pf)\n", + "logger_pf.log_attribute(\"i12\", \"i_intf\", line_pf)\n", "\n", "# Simulation\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", @@ -88,52 +88,58 @@ "# DYNAMIC SIMULATION\n", "time_step_emt = time_step\n", "final_time_emt = final_time + time_step_emt\n", - "sim_name_emt = 'EMT_Slack_PiLine_PQLoad_with_PF_Init_EMT'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_emt)\n", + "sim_name_emt = \"EMT_Slack_PiLine_PQLoad_with_PF_Init_EMT\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_emt)\n", "\n", "# Components\n", "gnd = dpsimpy.emt.SimNode.gnd\n", - "n1_emt = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC)\n", - "n2_emt = dpsimpy.emt.SimNode('n2', dpsimpy.PhaseType.ABC)\n", + "n1_emt = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC)\n", + "n2_emt = dpsimpy.emt.SimNode(\"n2\", dpsimpy.PhaseType.ABC)\n", "\n", - "extnet_emt = dpsimpy.emt.ph3.NetworkInjection('Slack', dpsimpy.LogLevel.debug)\n", - "line_emt = dpsimpy.emt.ph3.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", + "extnet_emt = dpsimpy.emt.ph3.NetworkInjection(\"Slack\", dpsimpy.LogLevel.debug)\n", + "line_emt = dpsimpy.emt.ph3.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", "\n", - "line_emt.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(line_resistance),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(line_inductance),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(line_capacitance))\n", + "line_emt.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_resistance),\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_inductance),\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_capacitance),\n", + ")\n", "\n", - "load_emt = dpsimpy.emt.ph3.RXLoad('Load', dpsimpy.LogLevel.debug)\n", - "load_emt.set_parameters(dpsimpy.Math.single_phase_power_to_three_phase(p_load_nom),\n", - " dpsimpy.Math.single_phase_power_to_three_phase(q_load_nom),\n", - " V_nom)\n", + "load_emt = dpsimpy.emt.ph3.RXLoad(\"Load\", dpsimpy.LogLevel.debug)\n", + "load_emt.set_parameters(\n", + " dpsimpy.Math.single_phase_power_to_three_phase(p_load_nom),\n", + " dpsimpy.Math.single_phase_power_to_three_phase(q_load_nom),\n", + " V_nom,\n", + ")\n", "\n", "\n", "# Topology\n", "extnet_emt.connect([n1_emt])\n", "line_emt.connect([n1_emt, n2_emt])\n", "load_emt.connect([n2_emt])\n", - "system_emt = dpsimpy.SystemTopology(50, [n1_emt, n2_emt], [extnet_emt, line_emt, load_emt])\n", + "system_emt = dpsimpy.SystemTopology(\n", + " 50, [n1_emt, n2_emt], [extnet_emt, line_emt, load_emt]\n", + ")\n", "\n", "# Initialization of dynamic topology\n", "system_emt.init_with_powerflow(system_pf, dpsimpy.Domain.EMT)\n", "\n", "# Logging\n", "logger_emt = dpsimpy.Logger(sim_name_emt)\n", - "logger_emt.log_attribute('v1', 'v', n1_emt)\n", - "logger_emt.log_attribute('v2', 'v', n2_emt)\n", - "logger_emt.log_attribute('i12', 'i_intf', line_emt)\n", - "logger_emt.log_attribute('irx', 'i_intf', load_emt)\n", + "logger_emt.log_attribute(\"v1\", \"v\", n1_emt)\n", + "logger_emt.log_attribute(\"v2\", \"v\", n2_emt)\n", + "logger_emt.log_attribute(\"i12\", \"i_intf\", line_emt)\n", + "logger_emt.log_attribute(\"irx\", \"i_intf\", load_emt)\n", "\n", "# load step sized in absolute terms\n", "load_switch = dpsimpy.emt.ph3.Switch(\"Load_Add_Switch_n2\", dpsimpy.LogLevel.debug)\n", - "connection_node = system_emt.node('n2')\n", - "resistance = np.abs(connection_node.initial_single_voltage())**2 / 100e3\n", - "load_switch.set_parameters(np.identity(3)*1e9, np.identity(3)*resistance)\n", + "connection_node = system_emt.node(\"n2\")\n", + "resistance = np.abs(connection_node.initial_single_voltage()) ** 2 / 100e3\n", + "load_switch.set_parameters(np.identity(3) * 1e9, np.identity(3) * resistance)\n", "load_switch.open()\n", "system_emt.add(load_switch)\n", - "system_emt.connect_component(load_switch, [gnd, system_emt.node('n2')])\n", - "logger_emt.log_attribute('switchedload_i', 'i_intf', load_switch)\n", + "system_emt.connect_component(load_switch, [gnd, system_emt.node(\"n2\")])\n", + "logger_emt.log_attribute(\"switchedload_i\", \"i_intf\", load_switch)\n", "load_step_event = dpsimpy.event.SwitchEvent3Ph(0.1 - time_step_emt, load_switch, True)\n", "\n", "# Simulation\n", @@ -175,23 +181,23 @@ "# POWERFLOW FOR INITIALIZATION\n", "time_step_pf = final_time\n", "final_time_pf = final_time + time_step_pf\n", - "sim_name_pf = 'DP_Slack_PiLine_PQLoad_with_PF_Init_PF'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "sim_name_pf = \"DP_Slack_PiLine_PQLoad_with_PF_Init_PF\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "\n", "# Components\n", - "n1_pf = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single)\n", - "n2_pf = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + "n1_pf = dpsimpy.sp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + "n2_pf = dpsimpy.sp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", - "extnet_pf = dpsimpy.sp.ph1.NetworkInjection('Slack', dpsimpy.LogLevel.debug)\n", + "extnet_pf = dpsimpy.sp.ph1.NetworkInjection(\"Slack\", dpsimpy.LogLevel.debug)\n", "extnet_pf.set_parameters(voltage_set_point=V_nom)\n", "extnet_pf.set_base_voltage(V_nom)\n", "extnet_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "\n", - "line_pf = dpsimpy.sp.ph1.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", + "line_pf = dpsimpy.sp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", "line_pf.set_parameters(R=line_resistance, L=line_inductance, C=line_capacitance)\n", "line_pf.set_base_voltage(V_nom)\n", "\n", - "load_pf = dpsimpy.sp.ph1.Shunt('Load', dpsimpy.LogLevel.debug)\n", + "load_pf = dpsimpy.sp.ph1.Shunt(\"Load\", dpsimpy.LogLevel.debug)\n", "load_pf.set_parameters(G=p_load_nom / V_nom**2, B=-q_load_nom / V_nom**2)\n", "load_pf.set_base_voltage(V_nom)\n", "\n", @@ -203,9 +209,9 @@ "\n", "# Logging\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", - "logger_pf.log_attribute('v1', 'v', n1_pf)\n", - "logger_pf.log_attribute('v2', 'v', n2_pf)\n", - "logger_pf.log_attribute('i12', 'i_intf', line_pf)\n", + "logger_pf.log_attribute(\"v1\", \"v\", n1_pf)\n", + "logger_pf.log_attribute(\"v2\", \"v\", n2_pf)\n", + "logger_pf.log_attribute(\"i12\", \"i_intf\", line_pf)\n", "\n", "# Simulation\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", @@ -222,21 +228,21 @@ "# DYNAMIC SIMULATION\n", "time_step_dp = time_step\n", "final_time_dp = final_time + time_step_dp\n", - "sim_name_dp = 'DP_Slack_PiLine_PQLoad_with_PF_Init_DP'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_dp)\n", + "sim_name_dp = \"DP_Slack_PiLine_PQLoad_with_PF_Init_DP\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_dp)\n", "\n", "# Components\n", "gnd = dpsimpy.dp.SimNode.gnd\n", - "n1_dp = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single)\n", - "n2_dp = dpsimpy.dp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + "n1_dp = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + "n2_dp = dpsimpy.dp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", - "extnet_dp = dpsimpy.dp.ph1.NetworkInjection('Slack', dpsimpy.LogLevel.debug)\n", + "extnet_dp = dpsimpy.dp.ph1.NetworkInjection(\"Slack\", dpsimpy.LogLevel.debug)\n", "extnet_dp.set_parameters(complex(V_nom, 0))\n", "\n", - "line_dp = dpsimpy.dp.ph1.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", + "line_dp = dpsimpy.dp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", "line_dp.set_parameters(line_resistance, line_inductance, line_capacitance)\n", "\n", - "load_dp = dpsimpy.dp.ph1.RXLoad('Load', dpsimpy.LogLevel.debug)\n", + "load_dp = dpsimpy.dp.ph1.RXLoad(\"Load\", dpsimpy.LogLevel.debug)\n", "load_dp.set_parameters(p_load_nom, q_load_nom, V_nom)\n", "\n", "# Topology\n", @@ -250,20 +256,20 @@ "\n", "# Logging\n", "logger_dp = dpsimpy.Logger(sim_name_dp)\n", - "logger_dp.log_attribute('v1', 'v', n1_dp)\n", - "logger_dp.log_attribute('v2', 'v', n2_dp)\n", - "logger_dp.log_attribute('i12', 'i_intf', line_dp)\n", - "logger_dp.log_attribute('irx', 'i_intf', load_dp)\n", + "logger_dp.log_attribute(\"v1\", \"v\", n1_dp)\n", + "logger_dp.log_attribute(\"v2\", \"v\", n2_dp)\n", + "logger_dp.log_attribute(\"i12\", \"i_intf\", line_dp)\n", + "logger_dp.log_attribute(\"irx\", \"i_intf\", load_dp)\n", "\n", "# load step sized in absolute terms\n", "load_switch = dpsimpy.dp.ph1.Switch(\"Load_Add_Switch_n2\", dpsimpy.LogLevel.debug)\n", - "connection_node = system_dp.node('n2')\n", - "resistance = np.abs(connection_node.initial_single_voltage())**2 / 100e3\n", + "connection_node = system_dp.node(\"n2\")\n", + "resistance = np.abs(connection_node.initial_single_voltage()) ** 2 / 100e3\n", "load_switch.set_parameters(1e9, resistance)\n", "load_switch.open()\n", "system_dp.add(load_switch)\n", - "system_dp.connect_component(load_switch, [gnd, system_dp.node('n2')])\n", - "logger_dp.log_attribute('switchedload_i', 'i_intf', load_switch)\n", + "system_dp.connect_component(load_switch, [gnd, system_dp.node(\"n2\")])\n", + "logger_dp.log_attribute(\"switchedload_i\", \"i_intf\", load_switch)\n", "load_step_event = dpsimpy.event.SwitchEvent(0.1 - time_step_dp, load_switch, True)\n", "\n", "# Simulation\n", @@ -290,14 +296,14 @@ "metadata": {}, "outputs": [], "source": [ - "model_name = 'Slack_PiLine_PQLoad_with_PF_Init'\n", + "model_name = \"Slack_PiLine_PQLoad_with_PF_Init\"\n", "\n", - "path_DP = 'logs/' + 'DP_' + model_name + '_DP/'\n", - "dpsim_result_file_DP = path_DP + 'DP_' + model_name + '_DP.csv'\n", + "path_DP = \"logs/\" + \"DP_\" + model_name + \"_DP/\"\n", + "dpsim_result_file_DP = path_DP + \"DP_\" + model_name + \"_DP.csv\"\n", "ts_dpsim_DP = read_timeseries_csv(dpsim_result_file_DP)\n", "\n", - "path_EMT = 'logs/' + 'EMT_' + model_name + '_EMT/'\n", - "dpsim_result_file_EMT = path_EMT + 'EMT_' + model_name + '_EMT.csv'\n", + "path_EMT = \"logs/\" + \"EMT_\" + model_name + \"_EMT/\"\n", + "dpsim_result_file_EMT = path_EMT + \"EMT_\" + model_name + \"_EMT.csv\"\n", "ts_dpsim_EMT = read_timeseries_csv(dpsim_result_file_EMT)" ] }, @@ -316,15 +322,24 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "\n", - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", + "\n", + "var_names = [\"v1\", \"v2\"]\n", + "for var_name in var_names:\n", + " plt.plot(\n", + " ts_dpsim_EMT[var_name + \"_0\"].interpolate(50e-6).time,\n", + " np.sqrt(3 / 2) * ts_dpsim_EMT[var_name + \"_0\"].interpolate(50e-6).values,\n", + " label=\"EMT\",\n", + " )\n", + " plt.plot(\n", + " ts_dpsim_DP[var_name].interpolate(50e-6).time,\n", + " ts_dpsim_DP[var_name].interpolate(50e-6).frequency_shift(50).values,\n", + " label=\"DP backshift\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", - "var_names = ['v1','v2']\n", - "for var_name in var_names: \n", - " plt.plot(ts_dpsim_EMT[var_name+'_0'].interpolate(50e-6).time, np.sqrt(3/2)*ts_dpsim_EMT[var_name+'_0'].interpolate(50e-6).values, label='EMT')\n", - " plt.plot(ts_dpsim_DP[var_name].interpolate(50e-6).time, ts_dpsim_DP[var_name].interpolate(50e-6).frequency_shift(50).values, label='DP backshift', linestyle='--')\n", - " \n", "plt.legend()\n", "plt.show()" ] @@ -342,14 +357,22 @@ "metadata": {}, "outputs": [], "source": [ - "var_name = 'i12'\n", - "\n", - "ts_emt_compare = TimeSeries('ts_emt_compare', ts_dpsim_EMT[var_name+'_0'].interpolate(50e-6).time, np.sqrt(3/2)*ts_dpsim_EMT[var_name+'_0'].interpolate(50e-6).values)\n", - "ts_dp_compare = TimeSeries('ts_dp_compare', ts_dpsim_DP[var_name].interpolate(50e-6).time, ts_dpsim_DP[var_name].interpolate(50e-6).frequency_shift(50).values)\n", - "\n", - "plt.figure(figsize=(12,8))\n", - "plt.plot(ts_emt_compare.time, ts_emt_compare.values, label='EMT')\n", - "plt.plot(ts_dp_compare.time, ts_dp_compare.values, label='DP backshift', linestyle='--')\n", + "var_name = \"i12\"\n", + "\n", + "ts_emt_compare = TimeSeries(\n", + " \"ts_emt_compare\",\n", + " ts_dpsim_EMT[var_name + \"_0\"].interpolate(50e-6).time,\n", + " np.sqrt(3 / 2) * ts_dpsim_EMT[var_name + \"_0\"].interpolate(50e-6).values,\n", + ")\n", + "ts_dp_compare = TimeSeries(\n", + " \"ts_dp_compare\",\n", + " ts_dpsim_DP[var_name].interpolate(50e-6).time,\n", + " ts_dpsim_DP[var_name].interpolate(50e-6).frequency_shift(50).values,\n", + ")\n", + "\n", + "plt.figure(figsize=(12, 8))\n", + "plt.plot(ts_emt_compare.time, ts_emt_compare.values, label=\"EMT\")\n", + "plt.plot(ts_dp_compare.time, ts_dp_compare.values, label=\"DP backshift\", linestyle=\"--\")\n", "plt.legend()\n", "plt.show()" ] diff --git a/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_DP_SynGenTrStab_SMIB_Fault.ipynb b/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_DP_SynGenTrStab_SMIB_Fault.ipynb index 7547add118..5027bd41c5 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_DP_SynGenTrStab_SMIB_Fault.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_DP_SynGenTrStab_SMIB_Fault.ipynb @@ -22,7 +22,7 @@ "import math\n", "import dpsimpy\n", "\n", - "#matplotlib widget" + "# matplotlib widget" ] }, { @@ -69,15 +69,15 @@ "Td0_s = 0.0300\n", "Tq0_s = 0.0700\n", "\n", - "# Operation point synchronous generator \n", + "# Operation point synchronous generator\n", "set_point_active_power = 300e6\n", - "set_point_voltage = 1.05*V_nom_MV\n", + "set_point_voltage = 1.05 * V_nom_MV\n", "\n", "# Breaker\n", "breaker_open = 1e9\n", "breaker_closed = 0.001\n", "\n", - "# Line \n", + "# Line\n", "line_lenght = 100\n", "line_resistance = 1.27e-4 * 529.0 * line_lenght * ratio**2\n", "line_inductance = 9.05e-4 * 529.0 * line_lenght * ratio**2 / nom_omega\n", @@ -85,7 +85,7 @@ "line_conductance = 8e-2\n", "\n", "# Simulation parameters\n", - "sim_name = \"EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault\";\n", + "sim_name = \"EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault\"\n", "final_time = 1.0\n", "time_step = 10e-6\n", "start_time_fault = 0.2" @@ -116,10 +116,13 @@ "\n", "# Synchronous generator ideal model\n", "gen_pf = dpsimpy.sp.ph1.SynchronGenerator(\"SynGen\", dpsimpy.LogLevel.debug)\n", - "gen_pf.set_parameters(rated_apparent_power=555e6, rated_voltage=24e3,\n", - " set_point_active_power=set_point_active_power,\n", - " set_point_voltage=set_point_voltage,\n", - " powerflow_bus_type=dpsimpy.PowerflowBusType.PV)\n", + "gen_pf.set_parameters(\n", + " rated_apparent_power=555e6,\n", + " rated_voltage=24e3,\n", + " set_point_active_power=set_point_active_power,\n", + " set_point_voltage=set_point_voltage,\n", + " powerflow_bus_type=dpsimpy.PowerflowBusType.PV,\n", + ")\n", "gen_pf.set_base_voltage(V_nom_MV)\n", "gen_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PV)\n", "\n", @@ -131,14 +134,18 @@ "\n", "# Line\n", "line_pf = dpsimpy.sp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", - "line_pf.set_parameters(line_resistance, line_inductance, line_capacitance, line_conductance)\n", + "line_pf.set_parameters(\n", + " line_resistance, line_inductance, line_capacitance, line_conductance\n", + ")\n", "line_pf.set_base_voltage(V_nom_MV)\n", "\n", "# Topology\n", "gen_pf.connect([n1_pf])\n", "line_pf.connect([n1_pf, n2_pf])\n", "extnet_pf.connect([n2_pf])\n", - "system_pf = dpsimpy.SystemTopology(nom_freq, [n1_pf, n2_pf], [gen_pf, line_pf, extnet_pf])\n", + "system_pf = dpsimpy.SystemTopology(\n", + " nom_freq, [n1_pf, n2_pf], [gen_pf, line_pf, extnet_pf]\n", + ")\n", "\n", "# Logging\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", @@ -175,7 +182,7 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir(\"logs/\"+sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Extract relevant powerflow results\n", "init_terminal_volt = np.abs(n1_pf.single_voltage() * dpsimpy.RMS3PH_TO_PEAK1PH)\n", @@ -192,12 +199,30 @@ "# Synch\n", "gen = dpsimpy.emt.ph3.SynchronGeneratorDQTrapez(\"SynGen\", dpsimpy.LogLevel.debug)\n", "gen.set_parameters_operational_per_unit(\n", - " nom_power=555e6, nom_volt=24e3, nom_freq=60, pole_number=2, nom_field_cur=1300,\n", - " Rs=Rs, Ld=Ld, Lq=Lq, Ld_t=Ld_t, Lq_t=Lq_t, Ld_s=Ld_s, Lq_s=Lq_s, Ll=Ll, Td0_t=Td0_t, Tq0_t=Tq0_t,\n", - " Td0_s=Td0_s, Tq0_s=Tq0_s, inertia=H, init_active_power=init_active_power, init_reactive_power=init_reactive_power,\n", - " init_terminal_volt=init_terminal_volt, init_volt_angle=init_volt_angle, init_field_voltage=7.0821,\n", - " init_mech_power=init_mech_power\n", - " \n", + " nom_power=555e6,\n", + " nom_volt=24e3,\n", + " nom_freq=60,\n", + " pole_number=2,\n", + " nom_field_cur=1300,\n", + " Rs=Rs,\n", + " Ld=Ld,\n", + " Lq=Lq,\n", + " Ld_t=Ld_t,\n", + " Lq_t=Lq_t,\n", + " Ld_s=Ld_s,\n", + " Lq_s=Lq_s,\n", + " Ll=Ll,\n", + " Td0_t=Td0_t,\n", + " Tq0_t=Tq0_t,\n", + " Td0_s=Td0_s,\n", + " Tq0_s=Tq0_s,\n", + " inertia=H,\n", + " init_active_power=init_active_power,\n", + " init_reactive_power=init_reactive_power,\n", + " init_terminal_volt=init_terminal_volt,\n", + " init_volt_angle=init_volt_angle,\n", + " init_field_voltage=7.0821,\n", + " init_mech_power=init_mech_power,\n", ")\n", "\n", "# Grid bus as Slack\n", @@ -205,15 +230,19 @@ "\n", "# Line\n", "line = dpsimpy.emt.ph3.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", - "line.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(line_resistance),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(line_inductance),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(line_capacitance),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(line_conductance))\n", + "line.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_resistance),\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_inductance),\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_capacitance),\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(line_conductance),\n", + ")\n", "\n", "# Breaker\n", "fault = dpsimpy.emt.ph3.Switch(\"Br_fault\", dpsimpy.LogLevel.debug)\n", - "fault.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(breaker_open),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(breaker_closed))\n", + "fault.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(breaker_open),\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(breaker_closed),\n", + ")\n", "fault.open()\n", "\n", "# Topology\n", @@ -285,7 +314,7 @@ "H = 5\n", "Xpd = 0.31\n", "Rs = 0.003 * 0\n", - "D=1.5\n", + "D = 1.5\n", "\n", "# Initialization parameters\n", "init_mech_power = 300e6\n", @@ -297,8 +326,8 @@ "\n", "# PiLine parameters calculated from CIGRE Benchmark system\n", "line_resistance = 6.7\n", - "line_inductance = 47.0/nom_omega\n", - "line_capacitance = 3.42e-4/nom_omega\n", + "line_inductance = 47.0 / nom_omega\n", + "line_capacitance = 3.42e-4 / nom_omega\n", "line_conductance = 0\n", "\n", "# Parameters for powerflow initialization\n", @@ -310,7 +339,7 @@ "switch_closed = 0.1\n", "\n", "# Simulation parameters\n", - "sim_name = \"DP_SynGenTrStab_SMIB_Fault\";\n", + "sim_name = \"DP_SynGenTrStab_SMIB_Fault\"\n", "final_time = 20\n", "time_step = 0.001\n", "start_fault_event = True\n", @@ -346,10 +375,13 @@ "\n", "# Synchronous generator ideal model\n", "gen_pf = dpsimpy.sp.ph1.SynchronGenerator(\"Generator\", dpsimpy.LogLevel.debug)\n", - "gen_pf.set_parameters(rated_apparent_power=nom_power, rated_voltage=nom_ph_ph_volt_RMS,\n", - " set_point_active_power=init_active_power,\n", - " set_point_voltage=set_point_voltage*t_ratio,\n", - " powerflow_bus_type=dpsimpy.PowerflowBusType.PV)\n", + "gen_pf.set_parameters(\n", + " rated_apparent_power=nom_power,\n", + " rated_voltage=nom_ph_ph_volt_RMS,\n", + " set_point_active_power=init_active_power,\n", + " set_point_voltage=set_point_voltage * t_ratio,\n", + " powerflow_bus_type=dpsimpy.PowerflowBusType.PV,\n", + ")\n", "gen_pf.set_base_voltage(V_nom)\n", "gen_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PV)\n", "\n", @@ -361,7 +393,9 @@ "\n", "# Line\n", "line_pf = dpsimpy.sp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", - "line_pf.set_parameters(line_resistance, line_inductance, line_capacitance, line_conductance)\n", + "line_pf.set_parameters(\n", + " line_resistance, line_inductance, line_capacitance, line_conductance\n", + ")\n", "line_pf.set_base_voltage(V_nom)\n", "\n", "# Switch\n", @@ -374,7 +408,9 @@ "fault_pf.connect([dpsimpy.sp.SimNode.gnd, n1_pf])\n", "line_pf.connect([n1_pf, n2_pf])\n", "extnet_pf.connect([n2_pf])\n", - "system_pf = dpsimpy.SystemTopology(nom_freq, [n1_pf, n2_pf], [gen_pf, line_pf, extnet_pf, fault_pf])\n", + "system_pf = dpsimpy.SystemTopology(\n", + " nom_freq, [n1_pf, n2_pf], [gen_pf, line_pf, extnet_pf, fault_pf]\n", + ")\n", "\n", "# Logging\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", @@ -407,8 +443,8 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name_dp = sim_name + \"_DP\" \n", - "dpsimpy.Logger.set_log_dir(\"logs/\"+sim_name_dp)\n", + "sim_name_dp = sim_name + \"_DP\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_dp)\n", "\n", "# Nodes\n", "n1_dp = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", @@ -418,8 +454,14 @@ "gen_dp = dpsimpy.dp.ph1.SynchronGeneratorTrStab(\"SynGen\", dpsimpy.LogLevel.debug)\n", "# Xpd is given in p.u of generator base at transfomer primary side and should be transformed to network side\n", "gen_dp.set_standard_parameters_PU(\n", - " nom_power=nom_power, nom_volt = nom_ph_ph_volt_RMS, nom_freq=nom_freq,\n", - " Xpd = Xpd*t_ratio**2, inertia=cmd_Inertia*H, Rs=Rs, D=cmd_Damping*D)\n", + " nom_power=nom_power,\n", + " nom_volt=nom_ph_ph_volt_RMS,\n", + " nom_freq=nom_freq,\n", + " Xpd=Xpd * t_ratio**2,\n", + " inertia=cmd_Inertia * H,\n", + " Rs=Rs,\n", + " D=cmd_Damping * D,\n", + ")\n", "\n", "init_apparent_power = gen_pf.get_apparent_power()\n", "gen_dp.set_initial_values(init_apparent_power, init_mech_power)\n", @@ -429,7 +471,9 @@ "\n", "# Line\n", "line_dp = dpsimpy.dp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", - "line_dp.set_parameters(line_resistance, line_inductance, line_capacitance, line_conductance)\n", + "line_dp.set_parameters(\n", + " line_resistance, line_inductance, line_capacitance, line_conductance\n", + ")\n", "\n", "# Switch\n", "fault_dp = dpsimpy.dp.ph1.varResSwitch(\"Br_fault\", dpsimpy.LogLevel.debug)\n", @@ -442,7 +486,9 @@ "line_dp.connect([n1_dp, n2_dp])\n", "extnet_dp.connect([n2_dp])\n", "fault_dp.connect([dpsimpy.dp.SimNode.gnd, n1_dp])\n", - "system_dp = dpsimpy.SystemTopology(nom_freq, [n1_dp, n2_dp], [gen_dp, line_dp, fault_dp, extnet_dp])\n", + "system_dp = dpsimpy.SystemTopology(\n", + " nom_freq, [n1_dp, n2_dp], [gen_dp, line_dp, fault_dp, extnet_dp]\n", + ")\n", "\n", "\n", "# Initialization of dynamic topology\n", @@ -484,11 +530,11 @@ "if start_fault_event:\n", " sw1 = dpsimpy.event.SwitchEvent(start_time_fault, fault_dp, True)\n", " sim_dp.add_event(sw1)\n", - " \n", + "\n", "if end_fault_event:\n", " sw2 = dpsimpy.event.SwitchEvent(end_time_fault, fault_dp, False)\n", " sim_dp.add_event(sw2)\n", - " \n", + "\n", "sim_dp.run()" ] }, @@ -506,10 +552,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault/'\n", - "log_name = 'EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_emt3ph_DQ7odTrapez = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault/\"\n", + "log_name = \"EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_emt3ph_DQ7odTrapez = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -526,10 +572,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_SynGenTrStab_SMIB_Fault_DP/'\n", - "log_name = 'DP_SynGenTrStab_SMIB_Fault_DP'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dp1ph_TrStab = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/DP_SynGenTrStab_SMIB_Fault_DP/\"\n", + "log_name = \"DP_SynGenTrStab_SMIB_Fault_DP\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dp1ph_TrStab = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -546,24 +592,32 @@ "metadata": {}, "outputs": [], "source": [ - "plt.style.use('default')\n", - "#plt.rcParams.update({'font.size': 22})\n", + "plt.style.use(\"default\")\n", + "# plt.rcParams.update({'font.size': 22})\n", "\n", - "timestep=10e-6;\n", - "t_begin=0\n", - "t_end=5\n", + "timestep = 10e-6\n", + "t_begin = 0\n", + "t_end = 5\n", "\n", "# Fault at t=0.1 s untill t=0.15s\n", - "begin_idx = int(t_begin/timestep)\n", - "end_idx= int(t_end/timestep)\n", + "begin_idx = int(t_begin / timestep)\n", + "end_idx = int(t_end / timestep)\n", + "\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator emf (V)\", fontsize=18)\n", + "\n", + "for name in [\"Ep\"]:\n", + " # plt.plot(ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).time[begin_idx:end_idx], np.sqrt(3/2)*ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Full model (9th order)')\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name]\n", + " .interpolate(timestep)\n", + " .frequency_shift(60)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator emf (V)', fontsize=18)\n", - "\n", - "for name in ['Ep']:\n", - " #plt.plot(ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).time[begin_idx:end_idx], np.sqrt(3/2)*ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).frequency_shift(60).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)', linestyle='--')\n", - " \n", "plt.legend()\n", "plt.show()" ] @@ -582,13 +636,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator terminal voltage (V)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator terminal voltage (V)\", fontsize=18)\n", + "\n", + "for name in [\"v_gen\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2)\n", + " * ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Full model (9th order)\",\n", + " )\n", + " # plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).frequency_shift(60).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)', linestyle='--')\n", "\n", - "for name in ['v_gen']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).time[begin_idx:end_idx], np.sqrt(3/2)*ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Full model (9th order)')\n", - " #plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).frequency_shift(60).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)', linestyle='--')\n", - " \n", "plt.legend(fontsize=14)\n", "plt.show()" ] @@ -607,12 +670,29 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator terminal current (V)', fontsize=18)\n", - "\n", - "for name in ['i_gen']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).time[begin_idx:end_idx], np.sqrt(3/2)*ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).frequency_shift(60).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator terminal current (V)\", fontsize=18)\n", + "\n", + "for name in [\"i_gen\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2)\n", + " * ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Full model (9th order)\",\n", + " )\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name]\n", + " .interpolate(timestep)\n", + " .frequency_shift(60)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -632,11 +712,28 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "\n", - "for name in ['v_line']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).time[begin_idx:end_idx], np.sqrt(3/2)*ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).frequency_shift(60).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "\n", + "for name in [\"v_line\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2)\n", + " * ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Full model (9th order)\",\n", + " )\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name]\n", + " .interpolate(timestep)\n", + " .frequency_shift(60)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -656,11 +753,28 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "\n", - "for name in ['i_line']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).time[begin_idx:end_idx], np.sqrt(3/2)*ts_emt3ph_DQ7odTrapez[name + '_0'].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).frequency_shift(60).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "\n", + "for name in [\"i_line\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2)\n", + " * ts_emt3ph_DQ7odTrapez[name + \"_0\"]\n", + " .interpolate(timestep)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Full model (9th order)\",\n", + " )\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name]\n", + " .interpolate(timestep)\n", + " .frequency_shift(60)\n", + " .values[begin_idx:end_idx],\n", + " label=name + \" Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -680,19 +794,31 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.xlabel('time (s)', fontsize=20)\n", - "plt.ylabel('Rotor frequency (Hz)', fontsize=20)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.xlabel(\"time (s)\", fontsize=20)\n", + "plt.ylabel(\"Rotor frequency (Hz)\", fontsize=20)\n", "plt.xticks(fontsize=18)\n", "plt.yticks(fontsize=18)\n", - "#plt.ylim(59,61)\n", - "\n", - "#if x_axis limits are changed above, change them again to consider the complete duration\n", - "\n", - "#ROCOF\n", - "for name in ['wr_gen']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).time[begin_idx:end_idx], ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).values[begin_idx:end_idx]*60, label='Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).values[begin_idx:end_idx]*60/377, label='Classical model (2nd order)', linestyle='--')\n", + "# plt.ylim(59,61)\n", + "\n", + "# if x_axis limits are changed above, change them again to consider the complete duration\n", + "\n", + "# ROCOF\n", + "for name in [\"wr_gen\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).values[begin_idx:end_idx]\n", + " * 60,\n", + " label=\"Full model (9th order)\",\n", + " )\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).values[begin_idx:end_idx]\n", + " * 60\n", + " / 377,\n", + " label=\"Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend(fontsize=18)\n", "plt.show()" @@ -712,13 +838,25 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Rotor angular velocity (rad/s)', fontsize=18)\n", - "\n", - "\n", - "for name in ['wr_gen']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).time[begin_idx:end_idx], 2*math.pi*60*ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).values[begin_idx:end_idx], label=name +' Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).values[begin_idx:end_idx], label=name + ' Classical model (2nd order)' , linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Rotor angular velocity (rad/s)\", fontsize=18)\n", + "\n", + "\n", + "for name in [\"wr_gen\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " 2\n", + " * math.pi\n", + " * 60\n", + " * ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).values[begin_idx:end_idx],\n", + " label=name + \" Full model (9th order)\",\n", + " )\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).values[begin_idx:end_idx],\n", + " label=name + \" Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -738,10 +876,23 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['delta_r']:\n", - " plt.plot(ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).time[begin_idx:end_idx], ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).values[begin_idx:end_idx]*180/3.14, label=name + ' Full model (9th order)')\n", - " plt.plot(ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx], ts_dp1ph_TrStab[name].interpolate(timestep).values[begin_idx:end_idx]*180/3.14, label=name + ' Classical model (2nd order)', linestyle='--')\n" + "plt.figure(figsize=(12, 8))\n", + "for name in [\"delta_r\"]:\n", + " plt.plot(\n", + " ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_emt3ph_DQ7odTrapez[name].interpolate(timestep).values[begin_idx:end_idx]\n", + " * 180\n", + " / 3.14,\n", + " label=name + \" Full model (9th order)\",\n", + " )\n", + " plt.plot(\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).time[begin_idx:end_idx],\n", + " ts_dp1ph_TrStab[name].interpolate(timestep).values[begin_idx:end_idx]\n", + " * 180\n", + " / 3.14,\n", + " label=name + \" Classical model (2nd order)\",\n", + " linestyle=\"--\",\n", + " )" ] }, { diff --git a/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_EMT_SynGenVBR_SMIB_Fault.ipynb b/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_EMT_SynGenVBR_SMIB_Fault.ipynb index 2efd159990..9e2258e02e 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_EMT_SynGenVBR_SMIB_Fault.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_EMT_SynGenVBR_SMIB_Fault.ipynb @@ -22,12 +22,17 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "timestep = 10e-6\n", "duration = 1.0\n", "\n", - "dpsim_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = dpsim_path + '/build/dpsim/examples/cxx/'" + "dpsim_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = dpsim_path + \"/build/dpsim/examples/cxx/\"" ] }, { @@ -43,13 +48,25 @@ "metadata": {}, "outputs": [], "source": [ - "model_name = 'EMT_SynGenDQ7odTrapez_SMIB_Fault'\n", + "model_name = \"EMT_SynGenDQ7odTrapez_SMIB_Fault\"\n", "\n", - "sim = subprocess.Popen([path_exec+model_name, '--name', model_name, '--timestep', str(timestep), '--duration', str(duration)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + model_name,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path_res = 'logs/' + model_name + '/'\n", - "dpsim_result_file_res = path_res + model_name + '.csv'\n", + "path_res = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file_res = path_res + model_name + \".csv\"\n", "ts_dcim = read_timeseries_csv(dpsim_result_file_res)" ] }, @@ -66,13 +83,25 @@ "metadata": {}, "outputs": [], "source": [ - "model_name = 'EMT_SynGenVBR_SMIB_Fault'\n", + "model_name = \"EMT_SynGenVBR_SMIB_Fault\"\n", "\n", - "sim = subprocess.Popen([path_exec+model_name, '--name', model_name, '--timestep', str(timestep), '--duration', str(duration)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + model_name,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path_res = 'logs/' + model_name + '/'\n", - "dpsim_result_file_res = path_res + model_name + '.csv'\n", + "path_res = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file_res = path_res + model_name + \".csv\"\n", "ts_vbr = read_timeseries_csv(dpsim_result_file_res)" ] }, @@ -89,11 +118,11 @@ "metadata": {}, "outputs": [], "source": [ - "t_begin=0\n", - "t_end=1\n", + "t_begin = 0\n", + "t_end = 1\n", "\n", - "begin_idx = int(t_begin/timestep)\n", - "end_idx= int(t_end/timestep)" + "begin_idx = int(t_begin / timestep)\n", + "end_idx = int(t_end / timestep)" ] }, { @@ -109,13 +138,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Network node voltage (V)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Network node voltage (V)\", fontsize=18)\n", + "\n", + "for name in [\"v1\", \"v2\"]:\n", + " plt.plot(\n", + " ts_dcim[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_dcim[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_vbr[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", - "for name in ['v1', 'v2']:\n", - " plt.plot(ts_dcim[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_dcim[name + '_0'].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_vbr[name + '_0'].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", - " \n", "plt.legend(fontsize=14)\n", "plt.show()" ] @@ -133,13 +171,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator terminal voltage (V)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator terminal voltage (V)\", fontsize=18)\n", + "\n", + "for name in [\"v_gen\"]:\n", + " plt.plot(\n", + " ts_dcim[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_dcim[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_vbr[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", - "for name in ['v_gen']:\n", - " plt.plot(ts_dcim[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_dcim[name + '_0'].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_vbr[name + '_0'].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", - " \n", "plt.legend(fontsize=14)\n", "plt.show()" ] @@ -157,12 +204,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator terminal current (A)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator terminal current (A)\", fontsize=18)\n", "\n", - "for name in ['i_gen']:\n", - " plt.plot(ts_dcim[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_dcim[name + '_0'].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_vbr[name + '_0'].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", + "for name in [\"i_gen\"]:\n", + " plt.plot(\n", + " ts_dcim[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_dcim[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_vbr[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -181,11 +237,20 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['v_line']:\n", - " plt.plot(ts_dcim[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_dcim[name + '_0'].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_vbr[name + '_0'].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", + "for name in [\"v_line\"]:\n", + " plt.plot(\n", + " ts_dcim[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_dcim[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_vbr[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -204,11 +269,20 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['i_line']:\n", - " plt.plot(ts_dcim[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_dcim[name + '_0'].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_vbr[name + '_0'].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", + "for name in [\"i_line\"]:\n", + " plt.plot(\n", + " ts_dcim[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_dcim[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_vbr[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -227,15 +301,24 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.xlabel('time (s)', fontsize=20)\n", - "plt.ylabel('Rotor frequency (Hz)', fontsize=20)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.xlabel(\"time (s)\", fontsize=20)\n", + "plt.ylabel(\"Rotor frequency (Hz)\", fontsize=20)\n", "plt.xticks(fontsize=18)\n", "plt.yticks(fontsize=18)\n", "\n", - "for name in ['wr_gen']:\n", - " plt.plot(ts_dcim[name].time[begin_idx:end_idx], ts_dcim[name].values[begin_idx:end_idx]*60, label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name].time[begin_idx:end_idx], ts_vbr[name].values[begin_idx:end_idx]*60, label=name+' (VBR)', linestyle='--')\n", + "for name in [\"wr_gen\"]:\n", + " plt.plot(\n", + " ts_dcim[name].time[begin_idx:end_idx],\n", + " ts_dcim[name].values[begin_idx:end_idx] * 60,\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name].time[begin_idx:end_idx],\n", + " ts_vbr[name].values[begin_idx:end_idx] * 60,\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend(fontsize=18)\n", "plt.show()" @@ -254,13 +337,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Rotor angular velocity (rad/s)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Rotor angular velocity (rad/s)\", fontsize=18)\n", "\n", "\n", - "for name in ['wr_gen']:\n", - " plt.plot(ts_dcim[name].time[begin_idx:end_idx], 2*math.pi*60*ts_dcim[name].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name].time[begin_idx:end_idx], 2*math.pi*60*ts_vbr[name].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", + "for name in [\"wr_gen\"]:\n", + " plt.plot(\n", + " ts_dcim[name].time[begin_idx:end_idx],\n", + " 2 * math.pi * 60 * ts_dcim[name].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name].time[begin_idx:end_idx],\n", + " 2 * math.pi * 60 * ts_vbr[name].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -279,10 +371,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['delta_r']:\n", - " plt.plot(ts_dcim[name].time[begin_idx:end_idx], ts_dcim[name].values[begin_idx:end_idx]*180/3.14, label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name].time[begin_idx:end_idx], ts_vbr[name].values[begin_idx:end_idx]*180/3.14, label=name+' (VBR)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "for name in [\"delta_r\"]:\n", + " plt.plot(\n", + " ts_dcim[name].time[begin_idx:end_idx],\n", + " ts_dcim[name].values[begin_idx:end_idx] * 180 / 3.14,\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name].time[begin_idx:end_idx],\n", + " ts_vbr[name].values[begin_idx:end_idx] * 180 / 3.14,\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -300,13 +401,31 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['T_e']:\n", - " plt.plot(ts_dcim[name].time[begin_idx:end_idx], ts_dcim[name].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name].time[begin_idx:end_idx], -ts_vbr[name].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", - "for name in ['T_m']:\n", - " plt.plot(ts_dcim[name].time[begin_idx:end_idx], ts_dcim[name].values[begin_idx:end_idx], label=name+' (DCIM)')\n", - " plt.plot(ts_vbr[name].time[begin_idx:end_idx], -ts_vbr[name].values[begin_idx:end_idx], label=name+' (VBR)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "for name in [\"T_e\"]:\n", + " plt.plot(\n", + " ts_dcim[name].time[begin_idx:end_idx],\n", + " ts_dcim[name].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name].time[begin_idx:end_idx],\n", + " -ts_vbr[name].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", + "for name in [\"T_m\"]:\n", + " plt.plot(\n", + " ts_dcim[name].time[begin_idx:end_idx],\n", + " ts_dcim[name].values[begin_idx:end_idx],\n", + " label=name + \" (DCIM)\",\n", + " )\n", + " plt.plot(\n", + " ts_vbr[name].time[begin_idx:end_idx],\n", + " -ts_vbr[name].values[begin_idx:end_idx],\n", + " label=name + \" (VBR)\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -325,14 +444,18 @@ "outputs": [], "source": [ "diff = {}\n", - "for name in ['v_gen_0', 'v_gen_1', 'v_gen_2']:\n", - " diff[name] = ts_dcim[name].rmse(ts_dcim[name], ts_vbr[name])/np.max(ts_dcim[name].values)\n", - " print(name + ': ' + str(diff[name]))\n", - " assert(diff[name]) < 1.86e-6\n", - "for name in ['i_gen_0', 'i_gen_1', 'i_gen_2']:\n", - " diff[name] = ts_dcim[name].rmse(ts_dcim[name], ts_vbr[name])/np.max(ts_dcim[name].values)\n", - " print(name + ': ' + str(diff[name]))\n", - " assert(diff[name]) < 5e-4" + "for name in [\"v_gen_0\", \"v_gen_1\", \"v_gen_2\"]:\n", + " diff[name] = ts_dcim[name].rmse(ts_dcim[name], ts_vbr[name]) / np.max(\n", + " ts_dcim[name].values\n", + " )\n", + " print(name + \": \" + str(diff[name]))\n", + " assert (diff[name]) < 1.86e-6\n", + "for name in [\"i_gen_0\", \"i_gen_1\", \"i_gen_2\"]:\n", + " diff[name] = ts_dcim[name].rmse(ts_dcim[name], ts_vbr[name]) / np.max(\n", + " ts_dcim[name].values\n", + " )\n", + " print(name + \": \" + str(diff[name]))\n", + " assert (diff[name]) < 5e-4" ] } ], diff --git a/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb b/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb index 9d8bb9bb82..4248baf750 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_SynGenDQ7odTrapez_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb @@ -22,15 +22,20 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "timestep = 10e-6\n", "duration = 1.0\n", "\n", - "begin_idx=0\n", - "end_idx=-1\n", + "begin_idx = 0\n", + "end_idx = -1\n", "\n", - "dpsim_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = dpsim_path + '/build/dpsim/examples/cxx/'" + "dpsim_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = dpsim_path + \"/build/dpsim/examples/cxx/\"" ] }, { @@ -46,13 +51,25 @@ "metadata": {}, "outputs": [], "source": [ - "model_name_fundamental = 'EMT_SynGenDQ7odTrapez_SMIB_Fault'\n", + "model_name_fundamental = \"EMT_SynGenDQ7odTrapez_SMIB_Fault\"\n", "\n", - "sim = subprocess.Popen([path_exec+model_name_fundamental, '--name', model_name_fundamental, '--timestep', str(timestep), '--duration', str(duration)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + model_name_fundamental,\n", + " \"--name\",\n", + " model_name_fundamental,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path_res = 'logs/' + model_name_fundamental + '/'\n", - "dpsim_result_file_res = path_res + model_name_fundamental + '.csv'\n", + "path_res = \"logs/\" + model_name_fundamental + \"/\"\n", + "dpsim_result_file_res = path_res + model_name_fundamental + \".csv\"\n", "ts_fundamental = read_timeseries_csv(dpsim_result_file_res)" ] }, @@ -69,13 +86,25 @@ "metadata": {}, "outputs": [], "source": [ - "model_name_operational = 'EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault'\n", + "model_name_operational = \"EMT_SynGenDQ7odTrapez_OperationalParams_SMIB_Fault\"\n", "\n", - "sim = subprocess.Popen([path_exec+model_name_operational, '--name', model_name_operational, '--timestep', str(timestep), '--duration', str(duration)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + model_name_operational,\n", + " \"--name\",\n", + " model_name_operational,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path_res = 'logs/' + model_name_operational + '/'\n", - "dpsim_result_file_res = path_res + model_name_operational + '.csv'\n", + "path_res = \"logs/\" + model_name_operational + \"/\"\n", + "dpsim_result_file_res = path_res + model_name_operational + \".csv\"\n", "ts_operational = read_timeseries_csv(dpsim_result_file_res)" ] }, @@ -92,12 +121,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator terminal current (V)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator terminal current (V)\", fontsize=18)\n", "\n", - "for name in ['i_gen']:\n", - " plt.plot(ts_fundamental[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_fundamental[name + '_0'].values[begin_idx:end_idx], label=name)\n", - " plt.plot(ts_operational[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_operational[name + '_0'].values[begin_idx:end_idx], linestyle='--', label=name)\n", + "for name in [\"i_gen\"]:\n", + " plt.plot(\n", + " ts_fundamental[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_fundamental[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name,\n", + " )\n", + " plt.plot(\n", + " ts_operational[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_operational[name + \"_0\"].values[begin_idx:end_idx],\n", + " linestyle=\"--\",\n", + " label=name,\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -109,7 +147,14 @@ "metadata": {}, "outputs": [], "source": [ - "assert(np.max(ts_fundamental[name + '_0'].values[begin_idx:end_idx]-ts_operational[name + '_0'].values[begin_idx:end_idx])/np.max(ts_fundamental[name + '_0'].values[begin_idx:end_idx]) < 1e-3)" + "assert (\n", + " np.max(\n", + " ts_fundamental[name + \"_0\"].values[begin_idx:end_idx]\n", + " - ts_operational[name + \"_0\"].values[begin_idx:end_idx]\n", + " )\n", + " / np.max(ts_fundamental[name + \"_0\"].values[begin_idx:end_idx])\n", + " < 1e-3\n", + ")" ] } ], diff --git a/examples/Notebooks/Circuits/Compare_EMT_SynGenVBR_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb b/examples/Notebooks/Circuits/Compare_EMT_SynGenVBR_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb index fc28812993..6c012e4cf3 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_SynGenVBR_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_SynGenVBR_OperationalParams_Vs_FundamentalParams_SMIB_Fault.ipynb @@ -22,15 +22,20 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "timestep = 10e-6\n", "duration = 1.0\n", "\n", - "begin_idx=0\n", - "end_idx=-1\n", + "begin_idx = 0\n", + "end_idx = -1\n", "\n", - "dpsim_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = dpsim_path + '/build/dpsim/examples/cxx/'" + "dpsim_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = dpsim_path + \"/build/dpsim/examples/cxx/\"" ] }, { @@ -46,13 +51,25 @@ "metadata": {}, "outputs": [], "source": [ - "model_name_fundamental = 'EMT_SynGenVBR_SMIB_Fault'\n", + "model_name_fundamental = \"EMT_SynGenVBR_SMIB_Fault\"\n", "\n", - "sim = subprocess.Popen([path_exec+model_name_fundamental, '--name', model_name_fundamental, '--timestep', str(timestep), '--duration', str(duration)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + model_name_fundamental,\n", + " \"--name\",\n", + " model_name_fundamental,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path_res = 'logs/' + model_name_fundamental + '/'\n", - "dpsim_result_file_res = path_res + model_name_fundamental + '.csv'\n", + "path_res = \"logs/\" + model_name_fundamental + \"/\"\n", + "dpsim_result_file_res = path_res + model_name_fundamental + \".csv\"\n", "ts_fundamental = read_timeseries_csv(dpsim_result_file_res)" ] }, @@ -69,13 +86,25 @@ "metadata": {}, "outputs": [], "source": [ - "model_name_operational = 'EMT_SynGenVBR_OperationalParams_SMIB_Fault'\n", + "model_name_operational = \"EMT_SynGenVBR_OperationalParams_SMIB_Fault\"\n", "\n", - "sim = subprocess.Popen([path_exec+model_name_operational, '--name', model_name_operational, '--timestep', str(timestep), '--duration', str(duration)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + model_name_operational,\n", + " \"--name\",\n", + " model_name_operational,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path_res = 'logs/' + model_name_operational + '/'\n", - "dpsim_result_file_res = path_res + model_name_operational + '.csv'\n", + "path_res = \"logs/\" + model_name_operational + \"/\"\n", + "dpsim_result_file_res = path_res + model_name_operational + \".csv\"\n", "ts_operational = read_timeseries_csv(dpsim_result_file_res)" ] }, @@ -92,12 +121,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "plt.ylabel('Generator terminal current (V)', fontsize=18)\n", + "plt.figure(figsize=(12, 8))\n", + "plt.ylabel(\"Generator terminal current (V)\", fontsize=18)\n", "\n", - "for name in ['i_gen']:\n", - " plt.plot(ts_fundamental[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_fundamental[name + '_0'].values[begin_idx:end_idx], label=name)\n", - " plt.plot(ts_operational[name + '_0'].time[begin_idx:end_idx], np.sqrt(3/2)*ts_operational[name + '_0'].values[begin_idx:end_idx], linestyle='--', label=name)\n", + "for name in [\"i_gen\"]:\n", + " plt.plot(\n", + " ts_fundamental[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_fundamental[name + \"_0\"].values[begin_idx:end_idx],\n", + " label=name,\n", + " )\n", + " plt.plot(\n", + " ts_operational[name + \"_0\"].time[begin_idx:end_idx],\n", + " np.sqrt(3 / 2) * ts_operational[name + \"_0\"].values[begin_idx:end_idx],\n", + " linestyle=\"--\",\n", + " label=name,\n", + " )\n", "\n", "plt.legend()\n", "plt.show()" @@ -109,7 +147,14 @@ "metadata": {}, "outputs": [], "source": [ - "assert(np.max(ts_fundamental[name + '_0'].values[begin_idx:end_idx]-ts_operational[name + '_0'].values[begin_idx:end_idx])/np.max(ts_fundamental[name + '_0'].values[begin_idx:end_idx]) < 1e-3)" + "assert (\n", + " np.max(\n", + " ts_fundamental[name + \"_0\"].values[begin_idx:end_idx]\n", + " - ts_operational[name + \"_0\"].values[begin_idx:end_idx]\n", + " )\n", + " / np.max(ts_fundamental[name + \"_0\"].values[begin_idx:end_idx])\n", + " < 1e-3\n", + ")" ] } ], diff --git a/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealCS_DP_WSCC_9bus_IdealVS.ipynb b/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealCS_DP_WSCC_9bus_IdealVS.ipynb index 365277d7ca..34eb46eb33 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealCS_DP_WSCC_9bus_IdealVS.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealCS_DP_WSCC_9bus_IdealVS.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09/WSCC-09'\n", - "filename = 'WSCC-09'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09/WSCC-09\"\n", + "filename = \"WSCC-09\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -46,16 +48,21 @@ "import os\n", "import subprocess\n", "\n", - "PEAK1PH_TO_RMS3PH=np.sqrt(3./2.)\n", + "PEAK1PH_TO_RMS3PH = np.sqrt(3.0 / 2.0)\n", "\n", - "name = 'DP_WSCC-9bus_IdealVS'\n", - "name_emt = 'EMT_WSCC-9bus_IdealCS'\n", + "name = \"DP_WSCC-9bus_IdealVS\"\n", + "name_emt = \"EMT_WSCC-9bus_IdealCS\"\n", "\n", "timestep = 100e-6\n", "duration = 0.1\n", "\n", - "root_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = root_path + '/build/dpsim/examples/cxx/'" + "root_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = root_path + \"/build/dpsim/examples/cxx/\"" ] }, { @@ -71,9 +78,35 @@ "metadata": {}, "outputs": [], "source": [ - "sim = subprocess.Popen([path_exec+name, '--timestep', str(timestep), '--duration', str(duration), files[0], files[1], files[2]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " files[0],\n", + " files[1],\n", + " files[2],\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", - "sim = subprocess.Popen([path_exec+name_emt, '--timestep', str(timestep), '--duration', str(duration), files[0], files[1], files[2]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_emt,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " files[0],\n", + " files[1],\n", + " files[2],\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())" ] }, @@ -90,19 +123,19 @@ "metadata": {}, "outputs": [], "source": [ - "model_name = 'DP_WSCC-9bus_IdealVS'\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "model_name = \"DP_WSCC-9bus_IdealVS\"\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_dp = read_timeseries_csv(dpsim_result_file)\n", "\n", - "model_name = 'EMT_WSCC-9bus_IdealCS'\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "model_name = \"EMT_WSCC-9bus_IdealCS\"\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt = read_timeseries_csv(dpsim_result_file)\n", "\n", - "model_name = 'EMT_WSCC-9bus_IdealCS_PF'\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "model_name = \"EMT_WSCC-9bus_IdealCS_PF\"\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_pf = read_timeseries_csv(dpsim_result_file)" ] }, @@ -119,14 +152,25 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for phase in ['0']: #, '1','2']:\n", - " for name in ['v1_'+phase, 'v2_'+phase, 'v3_'+phase]:\n", - " plt.plot(ts_dpsim_emt[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt[name].values, label=name + ' (EMT)')\n", - "for name in ['v1', 'v2', 'v3']:\n", - " plt.plot(ts_dpsim_dp[name].time, ts_dpsim_dp[name].abs().values, label=name + ' (DP)')\n", - "for name in ['BUS1.V', 'BUS2.V', 'BUS3.V']:\n", - " plt.plot(ts_dpsim_pf[name].time, ts_dpsim_pf[name].abs().values, label=name + ' (PF)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "for phase in [\"0\"]: # , '1','2']:\n", + " for name in [\"v1_\" + phase, \"v2_\" + phase, \"v3_\" + phase]:\n", + " plt.plot(\n", + " ts_dpsim_emt[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt[name].values,\n", + " label=name + \" (EMT)\",\n", + " )\n", + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " plt.plot(\n", + " ts_dpsim_dp[name].time, ts_dpsim_dp[name].abs().values, label=name + \" (DP)\"\n", + " )\n", + "for name in [\"BUS1.V\", \"BUS2.V\", \"BUS3.V\"]:\n", + " plt.plot(\n", + " ts_dpsim_pf[name].time,\n", + " ts_dpsim_pf[name].abs().values,\n", + " label=name + \" (PF)\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -144,11 +188,18 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['v1', 'v2', 'v3']:\n", - " plt.plot(ts_dpsim_dp[name].time, ts_dpsim_dp[name].phase().values, label=name + ' (DP)')\n", - "for name in ['BUS1.V', 'BUS2.V', 'BUS3.V']:\n", - " plt.plot(ts_dpsim_pf[name].time, ts_dpsim_pf[name].phase().values, label=name + ' (PF)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " plt.plot(\n", + " ts_dpsim_dp[name].time, ts_dpsim_dp[name].phase().values, label=name + \" (DP)\"\n", + " )\n", + "for name in [\"BUS1.V\", \"BUS2.V\", \"BUS3.V\"]:\n", + " plt.plot(\n", + " ts_dpsim_pf[name].time,\n", + " ts_dpsim_pf[name].phase().values,\n", + " label=name + \" (PF)\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -166,12 +217,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for phase in ['0']: #,'1','2']:\n", - " for name in ['GEN1.I_'+phase, 'GEN2.I_'+phase, 'GEN3.I_'+phase]:\n", - " plt.plot(ts_dpsim_emt[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt[name].values, label=name + '(EMT)')\n", - "for name in ['GEN1.I', 'GEN2.I', 'GEN3.I']:\n", - " plt.plot(ts_dpsim_dp[name].interpolate(timestep).time, ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60).values, label=name + '(DP)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "for phase in [\"0\"]: # ,'1','2']:\n", + " for name in [\"GEN1.I_\" + phase, \"GEN2.I_\" + phase, \"GEN3.I_\" + phase]:\n", + " plt.plot(\n", + " ts_dpsim_emt[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt[name].values,\n", + " label=name + \"(EMT)\",\n", + " )\n", + "for name in [\"GEN1.I\", \"GEN2.I\", \"GEN3.I\"]:\n", + " plt.plot(\n", + " ts_dpsim_dp[name].interpolate(timestep).time,\n", + " ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60).values,\n", + " label=name + \"(DP)\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -191,12 +251,17 @@ "source": [ "ts_emt_rms3ph = {}\n", "rmse_rel = {}\n", - "for name in ['GEN1.I', 'GEN2.I', 'GEN3.I']:\n", - " ts_emt_rms3ph[name+'_0'] = ts_dpsim_emt[name+'_0']\n", - " ts_emt_rms3ph[name+'_0'].values = PEAK1PH_TO_RMS3PH*ts_emt_rms3ph[name+'_0'].values\n", - " rmse_rel[name] = ts_dpsim_dp[name].rmse(ts_emt_rms3ph[name+'_0'], ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60))/np.max(ts_dpsim_dp[name].abs().values)\n", - " print('Rel. RMSE for {}: {}'.format(name, rmse_rel[name]))\n", - " assert(rmse_rel[name]<1e-2)" + "for name in [\"GEN1.I\", \"GEN2.I\", \"GEN3.I\"]:\n", + " ts_emt_rms3ph[name + \"_0\"] = ts_dpsim_emt[name + \"_0\"]\n", + " ts_emt_rms3ph[name + \"_0\"].values = (\n", + " PEAK1PH_TO_RMS3PH * ts_emt_rms3ph[name + \"_0\"].values\n", + " )\n", + " rmse_rel[name] = ts_dpsim_dp[name].rmse(\n", + " ts_emt_rms3ph[name + \"_0\"],\n", + " ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60),\n", + " ) / np.max(ts_dpsim_dp[name].abs().values)\n", + " print(\"Rel. RMSE for {}: {}\".format(name, rmse_rel[name]))\n", + " assert rmse_rel[name] < 1e-2" ] }, { diff --git a/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealVS_DP_WSCC_9bus_IdealVS.ipynb b/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealVS_DP_WSCC_9bus_IdealVS.ipynb index eb31a868aa..2b5768a42d 100644 --- a/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealVS_DP_WSCC_9bus_IdealVS.ipynb +++ b/examples/Notebooks/Circuits/Compare_EMT_WSCC_9bus_IdealVS_DP_WSCC_9bus_IdealVS.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09/WSCC-09'\n", - "filename = 'WSCC-09'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09/WSCC-09\"\n", + "filename = \"WSCC-09\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -48,16 +50,21 @@ "\n", "# %matplotlib widget\n", "\n", - "PEAK1PH_TO_RMS3PH=np.sqrt(3./2.)\n", + "PEAK1PH_TO_RMS3PH = np.sqrt(3.0 / 2.0)\n", "\n", - "name = 'DP_WSCC-9bus_IdealVS'\n", - "name_emt = 'EMT_WSCC-9bus_IdealVS'\n", + "name = \"DP_WSCC-9bus_IdealVS\"\n", + "name_emt = \"EMT_WSCC-9bus_IdealVS\"\n", "\n", "timestep = 10e-6\n", "duration = 0.1\n", "\n", - "root_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", - "path_exec = root_path + '/build/dpsim/examples/cxx/'" + "root_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", + "path_exec = root_path + \"/build/dpsim/examples/cxx/\"" ] }, { @@ -73,9 +80,35 @@ "metadata": {}, "outputs": [], "source": [ - "sim = subprocess.Popen([path_exec+name, '--timestep', str(timestep), '--duration', str(duration), files[0], files[1], files[2]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " files[0],\n", + " files[1],\n", + " files[2],\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", - "sim = subprocess.Popen([path_exec+name_emt, '--timestep', str(timestep), '--duration', str(duration), files[0], files[1], files[2]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_emt,\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " files[0],\n", + " files[1],\n", + " files[2],\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())" ] }, @@ -92,14 +125,14 @@ "metadata": {}, "outputs": [], "source": [ - "model_name = 'DP_WSCC-9bus_IdealVS'\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "model_name = \"DP_WSCC-9bus_IdealVS\"\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_dp = read_timeseries_csv(dpsim_result_file)\n", "\n", - "model_name = 'EMT_WSCC-9bus_IdealVS'\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "model_name = \"EMT_WSCC-9bus_IdealVS\"\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt = read_timeseries_csv(dpsim_result_file)" ] }, @@ -116,12 +149,18 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['v1', 'v2', 'v3']:\n", - " plt.plot(ts_dpsim_dp[name].time, ts_dpsim_dp[name].abs().values, label=name + '(DP)')\n", - "for phase in ['0']:\n", - " for name in ['v1_'+phase, 'v2_'+phase, 'v3_'+phase]:\n", - " plt.plot(ts_dpsim_emt[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt[name].values, label=name + '(EMT)')\n", + "plt.figure(figsize=(12, 8))\n", + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " plt.plot(\n", + " ts_dpsim_dp[name].time, ts_dpsim_dp[name].abs().values, label=name + \"(DP)\"\n", + " )\n", + "for phase in [\"0\"]:\n", + " for name in [\"v1_\" + phase, \"v2_\" + phase, \"v3_\" + phase]:\n", + " plt.plot(\n", + " ts_dpsim_emt[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt[name].values,\n", + " label=name + \"(EMT)\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -141,12 +180,17 @@ "source": [ "ts_emt_rms3ph = {}\n", "rmse_rel = {}\n", - "for name in ['v1', 'v2', 'v3']:\n", - " ts_emt_rms3ph[name+'_0'] = ts_dpsim_emt[name+'_0']\n", - " ts_emt_rms3ph[name+'_0'].values = PEAK1PH_TO_RMS3PH*ts_emt_rms3ph[name+'_0'].values\n", - " rmse_rel[name] = ts_dpsim_dp[name].rmse(ts_emt_rms3ph[name+'_0'], ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60))/np.max(ts_dpsim_dp[name].abs().values)\n", - " print('Rel. RMSE for {}: {}'.format(name, rmse_rel[name]))\n", - " assert(rmse_rel[name]<1e-5)" + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " ts_emt_rms3ph[name + \"_0\"] = ts_dpsim_emt[name + \"_0\"]\n", + " ts_emt_rms3ph[name + \"_0\"].values = (\n", + " PEAK1PH_TO_RMS3PH * ts_emt_rms3ph[name + \"_0\"].values\n", + " )\n", + " rmse_rel[name] = ts_dpsim_dp[name].rmse(\n", + " ts_emt_rms3ph[name + \"_0\"],\n", + " ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60),\n", + " ) / np.max(ts_dpsim_dp[name].abs().values)\n", + " print(\"Rel. RMSE for {}: {}\".format(name, rmse_rel[name]))\n", + " assert rmse_rel[name] < 1e-5" ] }, { @@ -162,9 +206,11 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['v1', 'v2', 'v3']:\n", - " plt.plot(ts_dpsim_dp[name].time, ts_dpsim_dp[name].phase().values, label=name + '(DP)')" + "plt.figure(figsize=(12, 8))\n", + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " plt.plot(\n", + " ts_dpsim_dp[name].time, ts_dpsim_dp[name].phase().values, label=name + \"(DP)\"\n", + " )" ] }, { @@ -180,12 +226,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for phase in ['0']:\n", - " for name in ['GEN1.I_'+phase, 'GEN2.I_'+phase, 'GEN3.I_'+phase]:\n", - " plt.plot(ts_dpsim_emt[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt[name].values, label=name + '(EMT)')\n", - "for name in ['GEN1.I', 'GEN2.I', 'GEN3.I']:\n", - " plt.plot(ts_dpsim_dp[name].time, ts_dpsim_dp[name].frequency_shift(60).values, label=name + '(DP)', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "for phase in [\"0\"]:\n", + " for name in [\"GEN1.I_\" + phase, \"GEN2.I_\" + phase, \"GEN3.I_\" + phase]:\n", + " plt.plot(\n", + " ts_dpsim_emt[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt[name].values,\n", + " label=name + \"(EMT)\",\n", + " )\n", + "for name in [\"GEN1.I\", \"GEN2.I\", \"GEN3.I\"]:\n", + " plt.plot(\n", + " ts_dpsim_dp[name].time,\n", + " ts_dpsim_dp[name].frequency_shift(60).values,\n", + " label=name + \"(DP)\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -205,12 +260,17 @@ "source": [ "ts_emt_rms3ph = {}\n", "rmse_rel = {}\n", - "for name in ['GEN1.I', 'GEN2.I', 'GEN3.I']:\n", - " ts_emt_rms3ph[name+'_0'] = ts_dpsim_emt[name+'_0']\n", - " ts_emt_rms3ph[name+'_0'].values = PEAK1PH_TO_RMS3PH*ts_emt_rms3ph[name+'_0'].values\n", - " rmse_rel[name] = ts_dpsim_dp[name].rmse(ts_emt_rms3ph[name+'_0'], ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60))/np.max(ts_dpsim_dp[name].abs().values)\n", - " print('Rel. RMSE for {}: {}'.format(name, rmse_rel[name]))\n", - " assert(rmse_rel[name]<1e-2)" + "for name in [\"GEN1.I\", \"GEN2.I\", \"GEN3.I\"]:\n", + " ts_emt_rms3ph[name + \"_0\"] = ts_dpsim_emt[name + \"_0\"]\n", + " ts_emt_rms3ph[name + \"_0\"].values = (\n", + " PEAK1PH_TO_RMS3PH * ts_emt_rms3ph[name + \"_0\"].values\n", + " )\n", + " rmse_rel[name] = ts_dpsim_dp[name].rmse(\n", + " ts_emt_rms3ph[name + \"_0\"],\n", + " ts_dpsim_dp[name].interpolate(timestep).frequency_shift(60),\n", + " ) / np.max(ts_dpsim_dp[name].abs().values)\n", + " print(\"Rel. RMSE for {}: {}\".format(name, rmse_rel[name]))\n", + " assert rmse_rel[name] < 1e-2" ] }, { diff --git a/examples/Notebooks/Circuits/DP_EMT_Validation_ReducedOrderSG_VBR_Load_Fault.ipynb b/examples/Notebooks/Circuits/DP_EMT_Validation_ReducedOrderSG_VBR_Load_Fault.ipynb index 89cc767c57..dab5d8680d 100644 --- a/examples/Notebooks/Circuits/DP_EMT_Validation_ReducedOrderSG_VBR_Load_Fault.ipynb +++ b/examples/Notebooks/Circuits/DP_EMT_Validation_ReducedOrderSG_VBR_Load_Fault.ipynb @@ -23,17 +23,30 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "\n", - "name = ['SP_ReducedOrderSG_VBR_Load_Fault', 'DP_ReducedOrderSG_VBR_Load_Fault', 'EMT_ReducedOrderSG_VBR_Load_Fault']\n", - "options = ['SGModel=3', 'SGModel=4', 'SGModel=6a', 'SGModel=6b']\n", + "name = [\n", + " \"SP_ReducedOrderSG_VBR_Load_Fault\",\n", + " \"DP_ReducedOrderSG_VBR_Load_Fault\",\n", + " \"EMT_ReducedOrderSG_VBR_Load_Fault\",\n", + "]\n", + "options = [\"SGModel=3\", \"SGModel=4\", \"SGModel=6a\", \"SGModel=6b\"]\n", "\n", - "dpsim_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", + "dpsim_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", "\n", - "path_exec = dpsim_path + '/build/dpsim/examples/cxx/'\n", + "path_exec = dpsim_path + \"/build/dpsim/examples/cxx/\"\n", "for i in range(len(name)):\n", - " for j in range (len(options)):\n", - " sim = subprocess.Popen([path_exec + name[i], '-o', options[j]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + " for j in range(len(options)):\n", + " sim = subprocess.Popen(\n", + " [path_exec + name[i], \"-o\", options[j]],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + " )\n", " print(sim.communicate()[0].decode())\n", " print(path_exec + name[i])" ] @@ -61,10 +74,10 @@ "import os\n", "\n", "work_dir = os.getcwd() + \"/logs/\"\n", - "file_name_3Order = 'SynGen3Order_VBR_Load_Fault'\n", - "file_name_4Order = 'SynGen4Order_VBR_Load_Fault'\n", - "file_name_6aOrder = 'SynGen6aOrder_VBR_Load_Fault'\n", - "file_name_6bOrder = 'SynGen6bOrder_VBR_Load_Fault'\n", + "file_name_3Order = \"SynGen3Order_VBR_Load_Fault\"\n", + "file_name_4Order = \"SynGen4Order_VBR_Load_Fault\"\n", + "file_name_6aOrder = \"SynGen6aOrder_VBR_Load_Fault\"\n", + "file_name_6bOrder = \"SynGen6bOrder_VBR_Load_Fault\"\n", "\n", "ts_dpsim_SP = []\n", "ts_dpsim_SP_shift = []\n", @@ -73,16 +86,22 @@ "ts_dpsim_EMT = []\n", "file_names = [file_name_3Order, file_name_4Order, file_name_6aOrder, file_name_6bOrder]\n", "for i in range(len(file_names)):\n", - " path_logfile = work_dir + \"SP_\" + file_names[i] + \"/\" + \"SP_\" + file_names[i] + \".csv\"\n", + " path_logfile = (\n", + " work_dir + \"SP_\" + file_names[i] + \"/\" + \"SP_\" + file_names[i] + \".csv\"\n", + " )\n", " ts_dpsim_SP.append(read_timeseries_dpsim(path_logfile))\n", " ts_dpsim_SP_shift.append(ts.frequency_shift_list(ts_dpsim_SP[i], 60))\n", - " \n", - " path_logfile = work_dir + \"DP_\" + file_names[i] + \"/\" + \"DP_\" + file_names[i] + \".csv\"\n", + "\n", + " path_logfile = (\n", + " work_dir + \"DP_\" + file_names[i] + \"/\" + \"DP_\" + file_names[i] + \".csv\"\n", + " )\n", " ts_dpsim_DP.append(read_timeseries_dpsim(path_logfile))\n", " ts_dpsim_DP_shift.append(ts.frequency_shift_list(ts_dpsim_DP[i], 60))\n", " print(path_logfile)\n", - " \n", - " path_logfile = work_dir + \"EMT_\" + file_names[i] + \"/\" + \"EMT_\" + file_names[i] + \".csv\"\n", + "\n", + " path_logfile = (\n", + " work_dir + \"EMT_\" + file_names[i] + \"/\" + \"EMT_\" + file_names[i] + \".csv\"\n", + " )\n", " ts_dpsim_EMT.append(read_timeseries_dpsim(path_logfile))" ] }, @@ -101,94 +120,161 @@ "source": [ "width = 16\n", "height = 4\n", - "color_EMT = 'black'\n", - "color_SP = 'C10'\n", - "color_DP = 'C11'\n", - "linestyle_EMT = '-'\n", - "linestyle_SP = '-'\n", - "linestyle_DP = 'dashed'\n", - "common_time=50e-6\n", - "roi_start=0\n", - "roi_end=4.5\n", - "roi = range(int(roi_start/common_time), int(roi_end/common_time))\n", + "color_EMT = \"black\"\n", + "color_SP = \"C10\"\n", + "color_DP = \"C11\"\n", + "linestyle_EMT = \"-\"\n", + "linestyle_SP = \"-\"\n", + "linestyle_DP = \"dashed\"\n", + "common_time = 50e-6\n", + "roi_start = 0\n", + "roi_end = 4.5\n", + "roi = range(int(roi_start / common_time), int(roi_end / common_time))\n", + "\n", "\n", "def plot_etorque(SGOrder):\n", - " if SGOrder==3:\n", - " idx=0\n", - " if SGOrder==4:\n", - " idx=1\n", - " if SGOrder==6:\n", + " if SGOrder == 3:\n", + " idx = 0\n", + " if SGOrder == 4:\n", + " idx = 1\n", + " if SGOrder == 6:\n", " # Marconato's model\n", - " idx=2\n", - " if SGOrder==7:\n", + " idx = 2\n", + " if SGOrder == 7:\n", " # Anderson's model\n", - " idx=3\n", - " \n", + " idx = 3\n", + "\n", " time = ts_dpsim_EMT[idx][\"Te\"].interpolate(common_time).time[roi]\n", " values_emt = ts_dpsim_EMT[idx][\"Te\"].interpolate(common_time).values[roi]\n", " values_sp = ts_dpsim_SP[idx][\"Te\"].interpolate(common_time).values[roi]\n", " values_dp = ts_dpsim_DP[idx][\"Te\"].interpolate(common_time).values[roi]\n", - " \n", + "\n", " fig = plt.figure(figsize=(width, height))\n", - " plt.plot(time, values_emt, label='EMT', linestyle=linestyle_EMT, color=color_EMT, linewidth=3) \n", - " plt.plot(time, values_sp, label='SP', color=color_SP, linestyle=linestyle_SP, linewidth=3) \n", - " plt.plot(time, values_dp, label='DP', color=color_DP, linestyle=linestyle_DP, linewidth=3) \n", - " plt.ylabel('Electrical torque (p.u.)')\n", - " plt.xlabel('Time (s)')\n", + " plt.plot(\n", + " time,\n", + " values_emt,\n", + " label=\"EMT\",\n", + " linestyle=linestyle_EMT,\n", + " color=color_EMT,\n", + " linewidth=3,\n", + " )\n", + " plt.plot(\n", + " time, values_sp, label=\"SP\", color=color_SP, linestyle=linestyle_SP, linewidth=3\n", + " )\n", + " plt.plot(\n", + " time, values_dp, label=\"DP\", color=color_DP, linestyle=linestyle_DP, linewidth=3\n", + " )\n", + " plt.ylabel(\"Electrical torque (p.u.)\")\n", + " plt.xlabel(\"Time (s)\")\n", " plt.xlim(0, 4.5)\n", " plt.grid()\n", - " plt.legend(loc='lower right')\n", + " plt.legend(loc=\"lower right\")\n", " plt.show()\n", - " \n", - " #calculate RMSE\n", - " nom_value = 0.540541 # power flow result\n", - " rmse_emt = ts_dpsim_SP[idx][\"Te\"].rmse(ts_dpsim_SP[idx][\"Te\"].interpolate(common_time), ts_dpsim_EMT[idx][\"Te\"].interpolate(common_time))\n", - " print('RMSE EMT = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) '.format(rmse_emt, rmse_emt/nom_value*100, nom_value))\n", - " rmse_dp = ts_dpsim_SP[idx][\"Te\"].rmse(ts_dpsim_SP[idx][\"Te\"].interpolate(common_time), ts_dpsim_DP[idx][\"Te\"].interpolate(common_time))\n", - " print('RMSE DP = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) '.format(rmse_dp, rmse_dp/nom_value*100, nom_value))\n", - " \n", - " return (rmse_emt/nom_value*100, rmse_dp/nom_value*100)\n", - " \n", - " \n", + "\n", + " # calculate RMSE\n", + " nom_value = 0.540541 # power flow result\n", + " rmse_emt = ts_dpsim_SP[idx][\"Te\"].rmse(\n", + " ts_dpsim_SP[idx][\"Te\"].interpolate(common_time),\n", + " ts_dpsim_EMT[idx][\"Te\"].interpolate(common_time),\n", + " )\n", + " print(\n", + " \"RMSE EMT = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) \".format(\n", + " rmse_emt, rmse_emt / nom_value * 100, nom_value\n", + " )\n", + " )\n", + " rmse_dp = ts_dpsim_SP[idx][\"Te\"].rmse(\n", + " ts_dpsim_SP[idx][\"Te\"].interpolate(common_time),\n", + " ts_dpsim_DP[idx][\"Te\"].interpolate(common_time),\n", + " )\n", + " print(\n", + " \"RMSE DP = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) \".format(\n", + " rmse_dp, rmse_dp / nom_value * 100, nom_value\n", + " )\n", + " )\n", + "\n", + " return (rmse_emt / nom_value * 100, rmse_dp / nom_value * 100)\n", + "\n", + "\n", "def plot_elecVar(SGOrder, variable_EMT, variable_SP, variable_DP, ylabel):\n", - " if SGOrder==3:\n", - " idx=0\n", - " if SGOrder==4:\n", - " idx=1\n", - " if SGOrder==6:\n", + " if SGOrder == 3:\n", + " idx = 0\n", + " if SGOrder == 4:\n", + " idx = 1\n", + " if SGOrder == 6:\n", " # Marconato's model\n", - " idx=2\n", - " if SGOrder==7:\n", + " idx = 2\n", + " if SGOrder == 7:\n", " # Anderson's model\n", - " idx=3\n", - " \n", + " idx = 3\n", + "\n", " time = ts_dpsim_EMT[idx][variable_EMT].interpolate(common_time).time[roi]\n", " values_emt = ts_dpsim_EMT[idx][variable_EMT].interpolate(common_time).values[roi]\n", - " values_sp = np.sqrt(2/3) * ts_dpsim_SP_shift[idx][variable_SP].interpolate(common_time).values[roi]\n", - " values_dp = np.sqrt(2/3) * ts_dpsim_DP_shift[idx][variable_DP].interpolate(common_time).values[roi] \n", - " \n", + " values_sp = (\n", + " np.sqrt(2 / 3)\n", + " * ts_dpsim_SP_shift[idx][variable_SP].interpolate(common_time).values[roi]\n", + " )\n", + " values_dp = (\n", + " np.sqrt(2 / 3)\n", + " * ts_dpsim_DP_shift[idx][variable_DP].interpolate(common_time).values[roi]\n", + " )\n", + "\n", " fig = plt.figure(figsize=(width, height))\n", - " plt.plot(time, values_emt, label='EMT', linestyle=linestyle_EMT, color=color_EMT, linewidth=3) \n", - " plt.plot(time, values_sp, label='SP', color=color_SP, linestyle=linestyle_SP, linewidth=3) \n", - " plt.plot(time, values_dp, label='DP', color=color_DP, linestyle=linestyle_DP, linewidth=3) \n", + " plt.plot(\n", + " time,\n", + " values_emt,\n", + " label=\"EMT\",\n", + " linestyle=linestyle_EMT,\n", + " color=color_EMT,\n", + " linewidth=3,\n", + " )\n", + " plt.plot(\n", + " time, values_sp, label=\"SP\", color=color_SP, linestyle=linestyle_SP, linewidth=3\n", + " )\n", + " plt.plot(\n", + " time, values_dp, label=\"DP\", color=color_DP, linestyle=linestyle_DP, linewidth=3\n", + " )\n", " plt.ylabel(ylabel)\n", - " plt.xlabel('Time (s)')\n", + " plt.xlabel(\"Time (s)\")\n", " plt.xlim(0.9, 1.2)\n", " plt.grid()\n", - " plt.legend(loc='lower right')\n", + " plt.legend(loc=\"lower right\")\n", " plt.show()\n", - " \n", - " #calculate RMSE\n", - " ts_dpsim_SP_real = TimeSeries(variable_SP, ts_dpsim_SP_shift[idx][variable_SP].time, np.sqrt(2/3) * ts_dpsim_SP_shift[idx][variable_SP].values.real)\n", - " rmse_emt = ts_dpsim_SP_real.rmse(ts_dpsim_SP_real.interpolate(common_time), ts_dpsim_EMT[idx][variable_EMT].interpolate(common_time))\n", - " nom_value = abs(max(ts_dpsim_SP_shift[idx][variable_SP].values[0:int(0.5/common_time)]))\n", - " print('RMSE EMT = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) '.format(rmse_emt, rmse_emt/nom_value*100, nom_value))\n", - " \n", - " ts_dpsim_DP_real = TimeSeries(variable_DP, ts_dpsim_DP_shift[idx][variable_DP].time, np.sqrt(2/3) * ts_dpsim_DP_shift[idx][variable_DP].values.real)\n", - " rmse_dp = ts_dpsim_SP_real.rmse(ts_dpsim_SP_real.interpolate(common_time), ts_dpsim_DP_real.interpolate(common_time))\n", - " print('RMSE DP = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) '.format(rmse_dp, rmse_dp/nom_value*100, nom_value))\n", - " \n", - " return (rmse_emt/nom_value*100, rmse_dp/nom_value*100)" + "\n", + " # calculate RMSE\n", + " ts_dpsim_SP_real = TimeSeries(\n", + " variable_SP,\n", + " ts_dpsim_SP_shift[idx][variable_SP].time,\n", + " np.sqrt(2 / 3) * ts_dpsim_SP_shift[idx][variable_SP].values.real,\n", + " )\n", + " rmse_emt = ts_dpsim_SP_real.rmse(\n", + " ts_dpsim_SP_real.interpolate(common_time),\n", + " ts_dpsim_EMT[idx][variable_EMT].interpolate(common_time),\n", + " )\n", + " nom_value = abs(\n", + " max(ts_dpsim_SP_shift[idx][variable_SP].values[0 : int(0.5 / common_time)])\n", + " )\n", + " print(\n", + " \"RMSE EMT = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) \".format(\n", + " rmse_emt, rmse_emt / nom_value * 100, nom_value\n", + " )\n", + " )\n", + "\n", + " ts_dpsim_DP_real = TimeSeries(\n", + " variable_DP,\n", + " ts_dpsim_DP_shift[idx][variable_DP].time,\n", + " np.sqrt(2 / 3) * ts_dpsim_DP_shift[idx][variable_DP].values.real,\n", + " )\n", + " rmse_dp = ts_dpsim_SP_real.rmse(\n", + " ts_dpsim_SP_real.interpolate(common_time),\n", + " ts_dpsim_DP_real.interpolate(common_time),\n", + " )\n", + " print(\n", + " \"RMSE DP = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) \".format(\n", + " rmse_dp, rmse_dp / nom_value * 100, nom_value\n", + " )\n", + " )\n", + "\n", + " return (rmse_emt / nom_value * 100, rmse_dp / nom_value * 100)" ] }, { @@ -275,16 +361,16 @@ "metadata": {}, "outputs": [], "source": [ - "tol = 0.001 # %\n", + "tol = 0.001 # %\n", "\n", - "assert(rmse_emt_3order 1 and step=='+str(load_idx))\n", + " for load_idx in range(1, max_step):\n", + " pd_test_list = pd_test.query(\"timestep > 1 and step==\" + str(load_idx))\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['v3_intpl_shift'])\n", + " test_list.append(row[\"values\"][\"v3_intpl_shift\"])\n", "\n", - " ref = pd_ref.query('timestep == 1 and step=='+str(load_idx)).iloc[0]['values']['v3_shift']\n", + " ref = pd_ref.query(\"timestep == 1 and step==\" + str(load_idx)).iloc[0][\n", + " \"values\"\n", + " ][\"v3_shift\"]\n", " mae_dp, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", " mae_dp_list.append(mae_dp)\n", - " \n", + "\n", " return mae_dp_list" ] }, @@ -104,14 +108,14 @@ "outputs": [], "source": [ "def calc_mae_dp_no_step(pd_ref, pd_test):\n", - " pd_test_list = pd_test.query('timestep > 1')\n", + " pd_test_list = pd_test.query(\"timestep > 1\")\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['v3_intpl_shift'])\n", + " test_list.append(row[\"values\"][\"v3_intpl_shift\"])\n", "\n", - " ref = pd_ref.query('timestep == 1').iloc[0]['values']['v3_shift']\n", + " ref = pd_ref.query(\"timestep == 1\").iloc[0][\"values\"][\"v3_shift\"]\n", " mae_dp, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", - " \n", + "\n", " return mae_dp" ] }, @@ -124,16 +128,18 @@ "def calc_mae_emt(pd_ref, pd_test, max_step=11):\n", " mae_emt_list = []\n", "\n", - " for load_idx in range(1,max_step): \n", - " pd_test_list = pd_test.query('timestep > 1 and step=='+str(load_idx))\n", + " for load_idx in range(1, max_step):\n", + " pd_test_list = pd_test.query(\"timestep > 1 and step==\" + str(load_idx))\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['v3_intpl'])\n", + " test_list.append(row[\"values\"][\"v3_intpl\"])\n", "\n", - " ref = pd_ref.query('timestep == 1 and step=='+str(load_idx)).iloc[0]['values']['v3']\n", + " ref = pd_ref.query(\"timestep == 1 and step==\" + str(load_idx)).iloc[0][\n", + " \"values\"\n", + " ][\"v3\"]\n", " mae, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", " mae_emt_list.append(mae)\n", - " \n", + "\n", " return mae_emt_list" ] }, @@ -143,15 +149,15 @@ "metadata": {}, "outputs": [], "source": [ - "def calc_mae_emt_no_step(pd_ref, pd_test): \n", - " pd_test_list = pd_test.query('timestep > 1')\n", + "def calc_mae_emt_no_step(pd_ref, pd_test):\n", + " pd_test_list = pd_test.query(\"timestep > 1\")\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['v3_intpl'])\n", + " test_list.append(row[\"values\"][\"v3_intpl\"])\n", "\n", - " ref = pd_ref.query('timestep == 1').iloc[0]['values']['v3']\n", + " ref = pd_ref.query(\"timestep == 1\").iloc[0][\"values\"][\"v3\"]\n", " mae, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", - " \n", + "\n", " return mae" ] }, @@ -170,31 +176,33 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'DP_RL_SourceStep_T' + str(ts_idx) + '/' \\\n", - " 'DP_RL_SourceStep_T' + str(ts_idx)\n", + "for ts_idx in range(1, 21):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"DP_RL_SourceStep_T\" + str(\n", + " ts_idx\n", + " ) + \"/\" \"DP_RL_SourceStep_T\" + str(ts_idx)\n", "\n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 50)\n", - " result_list.append({'timestep': ts_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_1 = pd.DataFrame(result_list)\n", "\n", "result_list = []\n", - "for ts_idx in range(40,401,20):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'DP_RL_SourceStep_T' + str(ts_idx) + '/' \\\n", - " 'DP_RL_SourceStep_T' + str(ts_idx)\n", + "for ts_idx in range(40, 401, 20):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"DP_RL_SourceStep_T\" + str(\n", + " ts_idx\n", + " ) + \"/\" \"DP_RL_SourceStep_T\" + str(ts_idx)\n", "\n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 50)\n", - " result_list.append({'timestep': ts_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_2 = pd.DataFrame(result_list)" ] }, @@ -206,18 +214,19 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(1,11):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'DP_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx) + '/' \\\n", - " 'DP_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(1, 11):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(\n", + " load_idx\n", + " ) + \"/\" \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 50)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_vstep_1 = pd.DataFrame(result_list)" ] }, @@ -227,8 +236,8 @@ "metadata": {}, "outputs": [], "source": [ - "curr = pd_dp_1.query('timestep=='+str(1))['values'].values[0]\n", - "plt.plot(curr['v3_shift'].time, curr['v3_shift'].values)" + "curr = pd_dp_1.query(\"timestep==\" + str(1))[\"values\"].values[0]\n", + "plt.plot(curr[\"v3_shift\"].time, curr[\"v3_shift\"].values)" ] }, { @@ -237,7 +246,7 @@ "metadata": {}, "outputs": [], "source": [ - "nom_amp = max(curr['v3_shift'].values)" + "nom_amp = max(curr[\"v3_shift\"].values)" ] }, { @@ -248,8 +257,10 @@ "source": [ "sourcestep = 9\n", "timestep = 20\n", - "curr = pd_dp_vstep_1.query('timestep=='+str(timestep)+' and step=='+str(sourcestep))['values'].values[0]\n", - "plt.plot(curr['v3_intpl_shift'].time, curr['v3_intpl_shift'].values)" + "curr = pd_dp_vstep_1.query(\n", + " \"timestep==\" + str(timestep) + \" and step==\" + str(sourcestep)\n", + ")[\"values\"].values[0]\n", + "plt.plot(curr[\"v3_intpl_shift\"].time, curr[\"v3_intpl_shift\"].values)" ] }, { @@ -268,21 +279,27 @@ "outputs": [], "source": [ "import matplotlib.ticker as ticker\n", + "\n", "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(0.0002))\n", "\n", - "timesteps = np.arange(2,21)*0.00005\n", - "for load_idx in range(1,10,4): \n", - " plt.plot(timesteps, mae_dp_list_1[load_idx] / nom_amp, 'o-', label=str(load_idx*10+10)+'% step')\n", - "#plt.ylim([-0.01,0.2])\n", - "#plt.xlim([0,0.0009])\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "for load_idx in range(1, 10, 4):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_list_1[load_idx] / nom_amp,\n", + " \"o-\",\n", + " label=str(load_idx * 10 + 10) + \"% step\",\n", + " )\n", + "# plt.ylim([-0.01,0.2])\n", + "# plt.xlim([0,0.0009])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_rl_source_step_voltage_1ms.pdf')" + "plt.savefig(\"dp_rl_source_step_voltage_1ms.pdf\")" ] }, { @@ -293,10 +310,17 @@ "source": [ "sourcestep = 4\n", "timestep = 15\n", - "curr = pd_dp_vstep_1.query('timestep=='+str(1)+' and step=='+str(sourcestep))['values'].values[0]\n", - "curr_vts = pd_dp_vstep_1.query('timestep=='+str(timestep)+' and step=='+str(sourcestep))['values'].values[0]\n", - "min_len = min(curr['v3_shift'].values.shape, curr_vts['v3_intpl_shift'].values.shape)[0]\n", - "plt.plot(curr['v3_shift'].time[:min_len], curr['v3_shift'].values[:min_len] - curr_vts['v3_intpl_shift'].values[:min_len])" + "curr = pd_dp_vstep_1.query(\"timestep==\" + str(1) + \" and step==\" + str(sourcestep))[\n", + " \"values\"\n", + "].values[0]\n", + "curr_vts = pd_dp_vstep_1.query(\n", + " \"timestep==\" + str(timestep) + \" and step==\" + str(sourcestep)\n", + ")[\"values\"].values[0]\n", + "min_len = min(curr[\"v3_shift\"].values.shape, curr_vts[\"v3_intpl_shift\"].values.shape)[0]\n", + "plt.plot(\n", + " curr[\"v3_shift\"].time[:min_len],\n", + " curr[\"v3_shift\"].values[:min_len] - curr_vts[\"v3_intpl_shift\"].values[:min_len],\n", + ")" ] }, { @@ -307,18 +331,19 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(40,401,20):\n", - " for load_idx in range(1,11):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'DP_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx) + '/' \\\n", - " 'DP_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(40, 401, 20):\n", + " for load_idx in range(1, 11):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(\n", + " load_idx\n", + " ) + \"/\" \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 50)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_vstep_2 = pd.DataFrame(result_list)" ] }, @@ -330,8 +355,10 @@ "source": [ "sourcestep = 2\n", "timestep = 360\n", - "curr = pd_dp_vstep_2.query('timestep=='+str(timestep)+' and step=='+str(sourcestep))['values'].values[0]\n", - "plt.plot(curr['v3_intpl_shift'].time, curr['v3_intpl_shift'].values)" + "curr = pd_dp_vstep_2.query(\n", + " \"timestep==\" + str(timestep) + \" and step==\" + str(sourcestep)\n", + ")[\"values\"].values[0]\n", + "plt.plot(curr[\"v3_intpl_shift\"].time, curr[\"v3_intpl_shift\"].values)" ] }, { @@ -349,18 +376,23 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(40,401,20)*0.00005\n", - "for load_idx in range(1,10,4): \n", - " plt.plot(timesteps, mae_dp_list_2[load_idx] / nom_amp, 'o-', label=str(load_idx*10+10)+'% step')\n", - "#plt.ylim([-0.01,0.2])\n", - "#plt.xlim([0,0.0009])\n", + "timesteps = np.arange(40, 401, 20) * 0.00005\n", + "for load_idx in range(1, 10, 4):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_list_2[load_idx] / nom_amp,\n", + " \"o-\",\n", + " label=str(load_idx * 10 + 10) + \"% step\",\n", + " )\n", + "# plt.ylim([-0.01,0.2])\n", + "# plt.xlim([0,0.0009])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_rl_source_step_voltage_20ms.pdf')" + "plt.savefig(\"dp_rl_source_step_voltage_20ms.pdf\")" ] }, { @@ -378,29 +410,31 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'EMT_RL_SourceStep_T' + str(ts_idx) + '/' \\\n", - " 'EMT_RL_SourceStep_T' + str(ts_idx)\n", + "for ts_idx in range(1, 21):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"EMT_RL_SourceStep_T\" + str(\n", + " ts_idx\n", + " ) + \"/\" \"EMT_RL_SourceStep_T\" + str(ts_idx)\n", "\n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_1 = pd.DataFrame(result_list)\n", "\n", "result_list = []\n", - "for ts_idx in range(40,401,20):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'EMT_RL_SourceStep_T' + str(ts_idx) + '/' \\\n", - " 'EMT_RL_SourceStep_T' + str(ts_idx)\n", + "for ts_idx in range(40, 401, 20):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"EMT_RL_SourceStep_T\" + str(\n", + " ts_idx\n", + " ) + \"/\" \"EMT_RL_SourceStep_T\" + str(ts_idx)\n", "\n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_2 = pd.DataFrame(result_list)" ] }, @@ -412,17 +446,18 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(1,11):\n", - " logs_dir = '../../../logs_source_step/'\n", - " log_name = logs_dir+'EMT_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx) + '/' \\\n", - " 'EMT_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(1, 11):\n", + " logs_dir = \"../../../logs_source_step/\"\n", + " log_name = logs_dir + \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(\n", + " load_idx\n", + " ) + \"/\" \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_vstep_1 = pd.DataFrame(result_list)" ] }, @@ -434,8 +469,10 @@ "source": [ "sourcestep = 1\n", "timestep = 20\n", - "curr = pd_emt_vstep_1.query('timestep=='+str(timestep)+' and step=='+str(sourcestep))['values'].values[0]\n", - "plt.plot(curr['v3_intpl'].time, curr['v3_intpl'].values)" + "curr = pd_emt_vstep_1.query(\n", + " \"timestep==\" + str(timestep) + \" and step==\" + str(sourcestep)\n", + ")[\"values\"].values[0]\n", + "plt.plot(curr[\"v3_intpl\"].time, curr[\"v3_intpl\"].values)" ] }, { @@ -453,22 +490,32 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(2,21)*0.00005\n", + "timesteps = np.arange(2, 21) * 0.00005\n", "\n", - "for i in range(1,10,4): \n", - " plt.plot(timesteps, mae_dp_list_1[i] / nom_amp, 'o-', label=str(i*10+10)+'% step, dp')\n", - "for i in range(1,10,4): \n", - " plt.plot(timesteps, mae_emt_list_1[i] / nom_amp, 'o-', label=str(i*10+10)+'% step, emt')\n", + "for i in range(1, 10, 4):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_list_1[i] / nom_amp,\n", + " \"o-\",\n", + " label=str(i * 10 + 10) + \"% step, dp\",\n", + " )\n", + "for i in range(1, 10, 4):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_emt_list_1[i] / nom_amp,\n", + " \"o-\",\n", + " label=str(i * 10 + 10) + \"% step, emt\",\n", + " )\n", "\n", - "#plt.ylim([-0.01,0.2])\n", - "#plt.xlim([0,0.0009])\n", + "# plt.ylim([-0.01,0.2])\n", + "# plt.xlim([0,0.0009])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_emt_rl_source_step_voltage_1ms.pdf')" + "plt.savefig(\"dp_emt_rl_source_step_voltage_1ms.pdf\")" ] }, { @@ -479,16 +526,17 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(40,401,20):\n", - " for load_idx in range(1,11):\n", - " log_dir = '../../../logs_source_step/'\n", - " log_name = log_dir + 'EMT_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx) + '/' \\\n", - " 'EMT_RL_SourceStep_T' + str(ts_idx) + '_V' + str(load_idx) \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(40, 401, 20):\n", + " for load_idx in range(1, 11):\n", + " log_dir = \"../../../logs_source_step/\"\n", + " log_name = log_dir + \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(\n", + " load_idx\n", + " ) + \"/\" \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_V\" + str(load_idx)\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_vstep_2 = pd.DataFrame(result_list)" ] }, @@ -500,8 +548,10 @@ "source": [ "sourcestep = 2\n", "timestep = 200\n", - "curr = pd_emt_vstep_2.query('timestep=='+str(timestep)+' and step=='+str(sourcestep))['values'].values[0]\n", - "plt.plot(curr['v3_intpl'].time, curr['v3_intpl'].values)" + "curr = pd_emt_vstep_2.query(\n", + " \"timestep==\" + str(timestep) + \" and step==\" + str(sourcestep)\n", + ")[\"values\"].values[0]\n", + "plt.plot(curr[\"v3_intpl\"].time, curr[\"v3_intpl\"].values)" ] }, { @@ -519,21 +569,31 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(40,401,20)*0.00005\n", + "timesteps = np.arange(40, 401, 20) * 0.00005\n", "\n", - "for load_idx in range(1,10,4): \n", - " plt.plot(timesteps, mae_dp_list_2[load_idx] / nom_amp, 'o-', label=str(load_idx*10+10)+'% step, dp')\n", + "for load_idx in range(1, 10, 4):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_list_2[load_idx] / nom_amp,\n", + " \"o-\",\n", + " label=str(load_idx * 10 + 10) + \"% step, dp\",\n", + " )\n", "\n", - "for load_idx in range(1,10,4): \n", - " plt.plot(timesteps, mae_emt_list_2[load_idx] / nom_amp, 'o-', label=str(load_idx*10+10)+'% step, emt')\n", + "for load_idx in range(1, 10, 4):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_emt_list_2[load_idx] / nom_amp,\n", + " \"o-\",\n", + " label=str(load_idx * 10 + 10) + \"% step, emt\",\n", + " )\n", "\n", - "#plt.ylim([0,0.1])\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "# plt.ylim([0,0.1])\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_emt_rl_source_step_voltage_20ms.pdf')" + "plt.savefig(\"dp_emt_rl_source_step_voltage_20ms.pdf\")" ] }, { @@ -558,18 +618,19 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(1,11):\n", - " log_dir = '../../../logs_source_step/'\n", - " log_name = log_dir + 'DP_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx) + '/' \\\n", - " 'DP_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx)\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(1, 11):\n", + " log_dir = \"../../../logs_source_step/\"\n", + " log_name = log_dir + \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(\n", + " load_idx\n", + " ) + \"/\" \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(load_idx)\n", "\n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 50)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_fstep_1 = pd.DataFrame(result_list)" ] }, @@ -581,8 +642,10 @@ "source": [ "sourcestep = 8\n", "timestep = 15\n", - "curr = pd_dp_fstep_1.query('timestep=='+str(timestep)+' and step=='+str(sourcestep))['values'].values[0]\n", - "plt.plot(curr['v3_intpl_shift'].time, curr['v3_intpl_shift'].values)" + "curr = pd_dp_fstep_1.query(\n", + " \"timestep==\" + str(timestep) + \" and step==\" + str(sourcestep)\n", + ")[\"values\"].values[0]\n", + "plt.plot(curr[\"v3_intpl_shift\"].time, curr[\"v3_intpl_shift\"].values)" ] }, { @@ -601,17 +664,22 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(2,21)*0.00005\n", - "plt.plot(timesteps, mae_dp_1 / nom_amp, 'o-', label='freq. dev. 0Hz')\n", - "for i in range(0,4,2): \n", - " plt.plot(timesteps, mae_dp_fstep_1[i] / nom_amp, 'o-', label='freq. dev. '+str(i+1)+'Hz')\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "plt.plot(timesteps, mae_dp_1 / nom_amp, \"o-\", label=\"freq. dev. 0Hz\")\n", + "for i in range(0, 4, 2):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_fstep_1[i] / nom_amp,\n", + " \"o-\",\n", + " label=\"freq. dev. \" + str(i + 1) + \"Hz\",\n", + " )\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_rl_source_step_frequency_1ms.pdf')" + "plt.savefig(\"dp_rl_source_step_frequency_1ms.pdf\")" ] }, { @@ -622,18 +690,19 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(40,401,20):\n", - " for load_idx in range(1,11):\n", - " log_dir = '../../../logs_source_step/'\n", - " log_name = log_dir + 'DP_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx) + '/' \\\n", - " 'DP_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(40, 401, 20):\n", + " for load_idx in range(1, 11):\n", + " log_dir = \"../../../logs_source_step/\"\n", + " log_name = log_dir + \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(\n", + " load_idx\n", + " ) + \"/\" \"DP_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 50)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_fstep_2 = pd.DataFrame(result_list)" ] }, @@ -653,17 +722,22 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(40,401,20)*0.00005\n", - "plt.plot(timesteps, mae_dp_2 / nom_amp, 'o-', label='freq. dev. 0Hz')\n", - "for i in range(0,4,2): \n", - " plt.plot(timesteps, mae_dp_fstep_2[i] / nom_amp, 'o-', label='freq. dev. '+str(i+1)+'Hz')\n", + "timesteps = np.arange(40, 401, 20) * 0.00005\n", + "plt.plot(timesteps, mae_dp_2 / nom_amp, \"o-\", label=\"freq. dev. 0Hz\")\n", + "for i in range(0, 4, 2):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_fstep_2[i] / nom_amp,\n", + " \"o-\",\n", + " label=\"freq. dev. \" + str(i + 1) + \"Hz\",\n", + " )\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_rl_source_step_frequency_20ms.pdf')" + "plt.savefig(\"dp_rl_source_step_frequency_20ms.pdf\")" ] }, { @@ -681,17 +755,18 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(1,11):\n", - " log_dir = '../../../logs_source_step/'\n", - " log_name = log_dir + 'EMT_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx) + '/' \\\n", - " 'EMT_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(1, 11):\n", + " log_dir = \"../../../logs_source_step/\"\n", + " log_name = log_dir + \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(\n", + " load_idx\n", + " ) + \"/\" \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_fstep_1 = pd.DataFrame(result_list)" ] }, @@ -711,22 +786,32 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(2,21)*0.00005\n", + "timesteps = np.arange(2, 21) * 0.00005\n", "\n", - "plt.plot(timesteps, mae_dp_1 / nom_amp, 'o-', label='freq. dev. 0Hz, dp')\n", - "for i in range(0,4,2): \n", - " plt.plot(timesteps, mae_dp_fstep_1[i] / nom_amp, 'o-', label='freq. dev. '+str(i+1)+'Hz, dp')\n", + "plt.plot(timesteps, mae_dp_1 / nom_amp, \"o-\", label=\"freq. dev. 0Hz, dp\")\n", + "for i in range(0, 4, 2):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_fstep_1[i] / nom_amp,\n", + " \"o-\",\n", + " label=\"freq. dev. \" + str(i + 1) + \"Hz, dp\",\n", + " )\n", "\n", - "plt.plot(timesteps, mae_emt_1 / nom_amp, 'o-', label='freq. dev. 0Hz, emt')\n", - "for i in range(0,4,2): \n", - " plt.plot(timesteps, mae_emt_fstep_1[i] / nom_amp, 'o-', label='freq. dev. '+str(i+1)+'Hz, emt')\n", + "plt.plot(timesteps, mae_emt_1 / nom_amp, \"o-\", label=\"freq. dev. 0Hz, emt\")\n", + "for i in range(0, 4, 2):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_emt_fstep_1[i] / nom_amp,\n", + " \"o-\",\n", + " label=\"freq. dev. \" + str(i + 1) + \"Hz, emt\",\n", + " )\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_emt_rl_source_step_frequency_1ms.pdf')" + "plt.savefig(\"dp_emt_rl_source_step_frequency_1ms.pdf\")" ] }, { @@ -737,17 +822,18 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(40,401,20):\n", - " for load_idx in range(1,11):\n", - " log_dir = '../../../logs_source_step/'\n", - " log_name = log_dir+'EMT_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx) + '/' \\\n", - " 'EMT_RL_SourceStep_T' + str(ts_idx) + '_F' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(40, 401, 20):\n", + " for load_idx in range(1, 11):\n", + " log_dir = \"../../../logs_source_step/\"\n", + " log_name = log_dir + \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(\n", + " load_idx\n", + " ) + \"/\" \"EMT_RL_SourceStep_T\" + str(ts_idx) + \"_F\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'step': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"step\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_fstep_2 = pd.DataFrame(result_list)" ] }, @@ -767,25 +853,35 @@ "metadata": {}, "outputs": [], "source": [ - "timesteps = np.arange(40,401,20)*0.00005\n", + "timesteps = np.arange(40, 401, 20) * 0.00005\n", + "\n", + "plt.plot(timesteps, mae_dp_2 / nom_amp, \"o-\", label=\"freq. dev. 0Hz, dp\")\n", + "for i in range(0, 4, 2):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_dp_fstep_2[i] / nom_amp,\n", + " \"o-\",\n", + " label=\"freq. dev. \" + str(i + 1) + \"Hz, dp\",\n", + " )\n", "\n", - "plt.plot(timesteps, mae_dp_2 / nom_amp, 'o-', label='freq. dev. 0Hz, dp')\n", - "for i in range(0,4,2): \n", - " plt.plot(timesteps, mae_dp_fstep_2[i] / nom_amp, 'o-', label='freq. dev. '+str(i+1)+'Hz, dp')\n", + "plt.plot(timesteps, mae_emt_2 / nom_amp, \"o-\", label=\"freq. dev. 0Hz, emt\")\n", + "for i in range(0, 4, 2):\n", + " plt.plot(\n", + " timesteps,\n", + " mae_emt_fstep_2[i] / nom_amp,\n", + " \"o-\",\n", + " label=\"freq. dev. \" + str(i + 1) + \"Hz, emt\",\n", + " )\n", "\n", - "plt.plot(timesteps, mae_emt_2 / nom_amp, 'o-', label='freq. dev. 0Hz, emt')\n", - "for i in range(0,4,2): \n", - " plt.plot(timesteps, mae_emt_fstep_2[i] / nom_amp, 'o-', label='freq. dev. '+str(i+1)+'Hz, emt')\n", - " \n", - "#plt.xlim([0.0015,0.008])\n", - "#plt.ylim([0,400])\n", - "#plt.ylim([0,0.1])\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean relative error voltage')\n", + "# plt.xlim([0.0015,0.008])\n", + "# plt.ylim([0,400])\n", + "# plt.ylim([0,0.1])\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean relative error voltage\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_emt_rl_source_step_frequency_20ms.pdf')" + "plt.savefig(\"dp_emt_rl_source_step_frequency_20ms.pdf\")" ] }, { diff --git a/examples/Notebooks/Circuits/SP_Slack_PiLine_VSI_with_PF_Init.ipynb b/examples/Notebooks/Circuits/SP_Slack_PiLine_VSI_with_PF_Init.ipynb index abf0935cbc..6417a12d54 100644 --- a/examples/Notebooks/Circuits/SP_Slack_PiLine_VSI_with_PF_Init.ipynb +++ b/examples/Notebooks/Circuits/SP_Slack_PiLine_VSI_with_PF_Init.ipynb @@ -67,22 +67,22 @@ "time_step_pf = final_time\n", "final_time_pf = final_time + time_step_pf\n", "sim_name_pf = sim_name + \"_PF\"\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "\n", "# Components\n", - "n1_pf = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single)\n", - "n2_pf = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + "n1_pf = dpsimpy.sp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + "n2_pf = dpsimpy.sp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", - "extnet_pf = dpsimpy.sp.ph1.NetworkInjection('Slack', dpsimpy.LogLevel.debug)\n", + "extnet_pf = dpsimpy.sp.ph1.NetworkInjection(\"Slack\", dpsimpy.LogLevel.debug)\n", "extnet_pf.set_parameters(voltage_set_point=V_nom)\n", "extnet_pf.set_base_voltage(V_nom)\n", "extnet_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "\n", - "line_pf = dpsimpy.sp.ph1.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", - "line_pf.set_parameters(R=0.5*5, L=0.5/314*5, C=50e-6/314*5)\n", + "line_pf = dpsimpy.sp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", + "line_pf.set_parameters(R=0.5 * 5, L=0.5 / 314 * 5, C=50e-6 / 314 * 5)\n", "line_pf.set_base_voltage(V_nom)\n", "\n", - "load_pf = dpsimpy.sp.ph1.Load('Load', dpsimpy.LogLevel.debug)\n", + "load_pf = dpsimpy.sp.ph1.Load(\"Load\", dpsimpy.LogLevel.debug)\n", "load_pf.set_parameters(active_power=-100e3, reactive_power=-50e3, nominal_voltage=20e3)\n", "load_pf.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PQ)\n", "\n", @@ -94,8 +94,8 @@ "\n", "# Logging\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", - "logger_pf.log_attribute('v1', 'v', n1_pf)\n", - "logger_pf.log_attribute('v2', 'v', n2_pf)\n", + "logger_pf.log_attribute(\"v1\", \"v\", n1_pf)\n", + "logger_pf.log_attribute(\"v2\", \"v\", n2_pf)\n", "\n", "# Simulation\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", @@ -125,28 +125,50 @@ "time_step_sp = time_step\n", "final_time_sp = final_time + time_step_sp\n", "sim_name_sp = sim_name + \"_SP\"\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_sp)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_sp)\n", "\n", "# Components\n", "gnd = dpsimpy.sp.SimNode.gnd\n", - "n1_sp = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single)\n", - "n2_sp = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single)\n", + "n1_sp = dpsimpy.sp.SimNode(\"n1\", dpsimpy.PhaseType.Single)\n", + "n2_sp = dpsimpy.sp.SimNode(\"n2\", dpsimpy.PhaseType.Single)\n", "\n", - "extnet_sp = dpsimpy.sp.ph1.NetworkInjection('Slack', dpsimpy.LogLevel.debug)\n", + "extnet_sp = dpsimpy.sp.ph1.NetworkInjection(\"Slack\", dpsimpy.LogLevel.debug)\n", "extnet_sp.set_parameters(complex(V_nom, 0))\n", "\n", - "line_sp = dpsimpy.sp.ph1.PiLine('PiLine', dpsimpy.LogLevel.debug)\n", - "line_sp.set_parameters(R=0.5*5, L=(0.5/314)*5, C=(50e-6/314)*5)\n", + "line_sp = dpsimpy.sp.ph1.PiLine(\"PiLine\", dpsimpy.LogLevel.debug)\n", + "line_sp.set_parameters(R=0.5 * 5, L=(0.5 / 314) * 5, C=(50e-6 / 314) * 5)\n", "\n", - "pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\"pv\", \"pv\", dpsimpy.LogLevel.debug, with_trafo=True)\n", + "pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv\", \"pv\", dpsimpy.LogLevel.debug, with_trafo=True\n", + ")\n", "pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=V_nom, p_ref=100e3, q_ref=50e3)\n", - "pv.set_controller_parameters(Kp_pll=cmd_scale_P * 0.25, Ki_pll=cmd_scale_I * 0.2,\n", - " Kp_power_ctrl=cmd_scale_P *0.001, Ki_power_ctrl=cmd_scale_I * 0.008 ,\n", - " Kp_curr_ctrl=cmd_scale_P * 0.3, Ki_curr_ctrl=cmd_scale_I * 1, omega_cutoff=2*np.pi*50)\n", - "pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - "pv.set_transformer_parameters(nom_voltage_end_1=V_nom, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=V_nom / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - "pv.set_initial_state_values(p_init=100e3, q_init=50e3, phi_d_init=0, phi_q_init=0, gamma_d_init=0, gamma_q_init=0)\n", + "pv.set_controller_parameters(\n", + " Kp_pll=cmd_scale_P * 0.25,\n", + " Ki_pll=cmd_scale_I * 0.2,\n", + " Kp_power_ctrl=cmd_scale_P * 0.001,\n", + " Ki_power_ctrl=cmd_scale_I * 0.008,\n", + " Kp_curr_ctrl=cmd_scale_P * 0.3,\n", + " Ki_curr_ctrl=cmd_scale_I * 1,\n", + " omega_cutoff=2 * np.pi * 50,\n", + ")\n", + "pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + "pv.set_transformer_parameters(\n", + " nom_voltage_end_1=V_nom,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=V_nom / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + ")\n", + "pv.set_initial_state_values(\n", + " p_init=100e3,\n", + " q_init=50e3,\n", + " phi_d_init=0,\n", + " phi_q_init=0,\n", + " gamma_d_init=0,\n", + " gamma_q_init=0,\n", + ")\n", "pv.with_control(pv_with_control)\n", "\n", "# Topology\n", @@ -160,45 +182,53 @@ "\n", "# Logging\n", "logger_sp = dpsimpy.Logger(sim_name_sp)\n", - "logger_sp.log_attribute('v1', 'v', n1_sp)\n", - "logger_sp.log_attribute('v2', 'v', n2_sp)\n", - "logger_sp.log_attribute('i12', 'i_intf', line_sp)\n", + "logger_sp.log_attribute(\"v1\", \"v\", n1_sp)\n", + "logger_sp.log_attribute(\"v2\", \"v\", n2_sp)\n", + "logger_sp.log_attribute(\"i12\", \"i_intf\", line_sp)\n", "\n", "\n", "input_names = [\n", - " \"pv_powerctrl_input_pref\", \"pv_powerctrl_input_qref\", \"pv_powerctrl_input_vcd\",\n", - " \"pv_powerctrl_input_vcq\", \"pv_powerctrl_input_ircd\", \"pv_powerctrl_input_ircq\"\n", + " \"pv_powerctrl_input_pref\",\n", + " \"pv_powerctrl_input_qref\",\n", + " \"pv_powerctrl_input_vcd\",\n", + " \"pv_powerctrl_input_vcq\",\n", + " \"pv_powerctrl_input_ircd\",\n", + " \"pv_powerctrl_input_ircq\",\n", "]\n", - "logger_sp.log_attribute(input_names, 'powerctrl_inputs', pv)\n", + "logger_sp.log_attribute(input_names, \"powerctrl_inputs\", pv)\n", "\n", "state_names = [\n", - " \"pv_powerctrl_state_p\", \"pv_powerctrl_state_q\", \"pv_powerctrl_state_phid\",\n", - " \"pv_powerctrl_state_phiq\", \"pv_powerctrl_state_gammad\", \"pv_powerctrl_state_gammaq\"\n", + " \"pv_powerctrl_state_p\",\n", + " \"pv_powerctrl_state_q\",\n", + " \"pv_powerctrl_state_phid\",\n", + " \"pv_powerctrl_state_phiq\",\n", + " \"pv_powerctrl_state_gammad\",\n", + " \"pv_powerctrl_state_gammaq\",\n", "]\n", - "logger_sp.log_attribute(state_names, 'powerctrl_states', pv)\n", + "logger_sp.log_attribute(state_names, \"powerctrl_states\", pv)\n", "\n", - "output_names = [\n", - " \"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"\n", - "]\n", + "output_names = [\"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"]\n", "\n", - "logger_sp.log_attribute(output_names, 'powerctrl_outputs', pv)\n", + "logger_sp.log_attribute(output_names, \"powerctrl_outputs\", pv)\n", "\n", - "logger_sp.log_attribute('pv_v_intf', 'v_intf', pv)\n", - "logger_sp.log_attribute('pv_i_intf', 'i_intf', pv)\n", - "logger_sp.log_attribute('pv_pll_output', 'pll_output', pv)\n", - "logger_sp.log_attribute('pv_vsref', 'Vsref', pv)\n", - "logger_sp.log_attribute('pv_vs', 'Vs', pv)\n", + "logger_sp.log_attribute(\"pv_v_intf\", \"v_intf\", pv)\n", + "logger_sp.log_attribute(\"pv_i_intf\", \"i_intf\", pv)\n", + "logger_sp.log_attribute(\"pv_pll_output\", \"pll_output\", pv)\n", + "logger_sp.log_attribute(\"pv_vsref\", \"Vsref\", pv)\n", + "logger_sp.log_attribute(\"pv_vs\", \"Vs\", pv)\n", "\n", "# load step sized in absolute terms\n", "load_switch = dpsimpy.sp.ph1.Switch(\"Load_Add_Switch_n2\", dpsimpy.LogLevel.debug)\n", - "connection_node = system_sp.node('n2')\n", - "resistance = np.abs(connection_node.initial_single_voltage())**2 / 10e6\n", + "connection_node = system_sp.node(\"n2\")\n", + "resistance = np.abs(connection_node.initial_single_voltage()) ** 2 / 10e6\n", "load_switch.set_parameters(1e9, resistance)\n", "load_switch.open()\n", "system_sp.add(load_switch)\n", - "system_sp.connect_component(load_switch, [gnd, system_sp.node('n2')])\n", - "logger_sp.log_attribute('switchedload_i', 'i_intf', load_switch)\n", - "load_step_event = dpsimpy.event.SwitchEvent(np.round(5.0/time_step)*time_step, load_switch, True)\n", + "system_sp.connect_component(load_switch, [gnd, system_sp.node(\"n2\")])\n", + "logger_sp.log_attribute(\"switchedload_i\", \"i_intf\", load_switch)\n", + "load_step_event = dpsimpy.event.SwitchEvent(\n", + " np.round(5.0 / time_step) * time_step, load_switch, True\n", + ")\n", "\n", "# Simulation\n", "sim_sp = dpsimpy.Simulation(sim_name_sp, dpsimpy.LogLevel.debug)\n", @@ -224,9 +254,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'SP_Slack_PiLine_VSI_with_PF_Init_PF'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"SP_Slack_PiLine_VSI_with_PF_Init_PF\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim_pf = read_timeseries_csv(dpsim_result_file)" ] @@ -244,9 +274,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'SP_Slack_PiLine_VSI_with_PF_Init_SP'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"SP_Slack_PiLine_VSI_with_PF_Init_SP\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -257,13 +287,13 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name == 'v1' or ts_name == 'v2':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name == \"v1\" or ts_name == \"v2\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", - "for ts_name, ts_obj in ts_dpsim_pf.items():\n", - " if ts_name == 'v1' or ts_name == 'v2':\n", - " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name+'_pf', linestyle=':')\n", + "for ts_name, ts_obj in ts_dpsim_pf.items():\n", + " if ts_name == \"v1\" or ts_name == \"v2\":\n", + " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name + \"_pf\", linestyle=\":\")\n", "plt.legend()\n", "plt.show()" ] diff --git a/examples/Notebooks/Circuits/SP_Validation_ReducedOrderSG_VBR_SMIB_Fault_withControllers.ipynb b/examples/Notebooks/Circuits/SP_Validation_ReducedOrderSG_VBR_SMIB_Fault_withControllers.ipynb index 01661e900f..7544de1814 100644 --- a/examples/Notebooks/Circuits/SP_Validation_ReducedOrderSG_VBR_SMIB_Fault_withControllers.ipynb +++ b/examples/Notebooks/Circuits/SP_Validation_ReducedOrderSG_VBR_SMIB_Fault_withControllers.ipynb @@ -28,17 +28,26 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "\n", - "name = 'SP_ReducedOrderSG_SMIB_Fault'\n", - "options = ['SGModel=3', 'SGModel=4', 'SGModel=6a', 'SGModel=6b']\n", + "name = \"SP_ReducedOrderSG_SMIB_Fault\"\n", + "options = [\"SGModel=3\", \"SGModel=4\", \"SGModel=6a\", \"SGModel=6b\"]\n", "\n", - "dpsim_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", + "dpsim_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", "\n", - "path_exec = dpsim_path + '/build/dpsim/examples/cxx/'\n", + "path_exec = dpsim_path + \"/build/dpsim/examples/cxx/\"\n", "for i in range(len(options)):\n", - " sim = subprocess.Popen([path_exec + name, '-o', options[i], '-oWithExciter=true', '-oFinalTime=10'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", - " print(sim.communicate()[0].decode())\n" + " sim = subprocess.Popen(\n", + " [path_exec + name, \"-o\", options[i], \"-oWithExciter=true\", \"-oFinalTime=10\"],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + " )\n", + " print(sim.communicate()[0].decode())" ] }, { @@ -66,10 +75,10 @@ "import os\n", "\n", "work_dir = os.getcwd() + \"/logs/\"\n", - "file_name_3Order = 'SP_SynGen3Order_VBR_SMIB_Fault'\n", - "file_name_4Order = 'SP_SynGen4Order_VBR_SMIB_Fault'\n", - "file_name_6aOrder = 'SP_SynGen6aOrder_VBR_SMIB_Fault'\n", - "file_name_6bOrder = 'SP_SynGen6bOrder_VBR_SMIB_Fault'\n", + "file_name_3Order = \"SP_SynGen3Order_VBR_SMIB_Fault\"\n", + "file_name_4Order = \"SP_SynGen4Order_VBR_SMIB_Fault\"\n", + "file_name_6aOrder = \"SP_SynGen6aOrder_VBR_SMIB_Fault\"\n", + "file_name_6bOrder = \"SP_SynGen6bOrder_VBR_SMIB_Fault\"\n", "\n", "\n", "path_logfile = work_dir + file_name_3Order + \"/\" + file_name_3Order + \".csv\"\n", @@ -103,21 +112,27 @@ "source": [ "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/SMIB-Fault/PSAT_3OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.txt'\n", - "local_file_3Order = 'reference-results/PSAT_3OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.out'\n", - "urllib.request.urlretrieve(url, local_file_3Order) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/SMIB-Fault/PSAT_3OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.txt\"\n", + "local_file_3Order = (\n", + " \"reference-results/PSAT_3OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.out\"\n", + ")\n", + "urllib.request.urlretrieve(url, local_file_3Order)\n", "ts_psat_3Order = read_timeseries_dpsim(local_file_3Order)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/SMIB-Fault/PSAT_4OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.txt'\n", - "local_file_4Order = 'reference-results/PSAT_4OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.out'\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/SMIB-Fault/PSAT_4OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.txt\"\n", + "local_file_4Order = (\n", + " \"reference-results/PSAT_4OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.out\"\n", + ")\n", "urllib.request.urlretrieve(url, local_file_4Order)\n", "ts_psat_4Order = read_timeseries_dpsim(local_file_4Order)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/SMIB-Fault/PSAT_6OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.txt'\n", - "local_file_6Order = 'reference-results/PSAT_6OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.out'\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/SMIB-Fault/PSAT_6OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.txt\"\n", + "local_file_6Order = (\n", + " \"reference-results/PSAT_6OrderSyGen_withExciter_SMIB_Fault_100mS_TS_1mS.out\"\n", + ")\n", "urllib.request.urlretrieve(url, local_file_6Order)\n", "ts_psat_6Order = read_timeseries_dpsim(local_file_6Order)" ] @@ -147,21 +162,21 @@ "metadata": {}, "outputs": [], "source": [ - "#calculate vd and vq\n", - "angle = ts_psat_3Order['delta'].values - ts_psat_3Order['theta_bus1'].values\n", - "V_bus1 = ts_psat_3Order['V_Bus1'].values\n", + "# calculate vd and vq\n", + "angle = ts_psat_3Order[\"delta\"].values - ts_psat_3Order[\"theta_bus1\"].values\n", + "V_bus1 = ts_psat_3Order[\"V_Bus1\"].values\n", "vd = V_bus1 * np.sin(angle)\n", - "ts_psat_3Order['vd'] = TimeSeries('vd', ts_psat_3Order['V_Bus1'].time, vd)\n", + "ts_psat_3Order[\"vd\"] = TimeSeries(\"vd\", ts_psat_3Order[\"V_Bus1\"].time, vd)\n", "vq = V_bus1 * np.cos(angle)\n", - "ts_psat_3Order['vq'] = TimeSeries('vq', ts_psat_3Order['V_Bus1'].time, vq)\n", + "ts_psat_3Order[\"vq\"] = TimeSeries(\"vq\", ts_psat_3Order[\"V_Bus1\"].time, vq)\n", "\n", - "#calculate id and iq in PSAT\n", + "# calculate id and iq in PSAT\n", "Xd_t = 0.299900\n", "Xq = 1.7600\n", - "i_d = (ts_psat_3Order['eq_t'].values - ts_psat_3Order['vq'].values) / Xd_t\n", - "ts_psat_3Order['id'] = TimeSeries('id', ts_psat_3Order['eq_t'].time, i_d)\n", - "i_q = ts_psat_3Order['vd'].values / Xq\n", - "ts_psat_3Order['iq'] = TimeSeries('iq', ts_psat_3Order['vd'].time, i_q)" + "i_d = (ts_psat_3Order[\"eq_t\"].values - ts_psat_3Order[\"vq\"].values) / Xd_t\n", + "ts_psat_3Order[\"id\"] = TimeSeries(\"id\", ts_psat_3Order[\"eq_t\"].time, i_d)\n", + "i_q = ts_psat_3Order[\"vd\"].values / Xq\n", + "ts_psat_3Order[\"iq\"] = TimeSeries(\"iq\", ts_psat_3Order[\"vd\"].time, i_q)" ] }, { @@ -180,21 +195,21 @@ "metadata": {}, "outputs": [], "source": [ - "#calculate vd and vq\n", - "angle = ts_psat_4Order['delta'].values - ts_psat_4Order['theta_bus1'].values\n", - "V_bus1 = ts_psat_4Order['V_Bus1'].values\n", + "# calculate vd and vq\n", + "angle = ts_psat_4Order[\"delta\"].values - ts_psat_4Order[\"theta_bus1\"].values\n", + "V_bus1 = ts_psat_4Order[\"V_Bus1\"].values\n", "vd = V_bus1 * np.sin(angle)\n", - "ts_psat_4Order['vd'] = TimeSeries('vd', ts_psat_4Order['V_Bus1'].time, vd)\n", + "ts_psat_4Order[\"vd\"] = TimeSeries(\"vd\", ts_psat_4Order[\"V_Bus1\"].time, vd)\n", "vq = V_bus1 * np.cos(angle)\n", - "ts_psat_4Order['vq'] = TimeSeries('vq', ts_psat_4Order['V_Bus1'].time, vq)\n", - " \n", - "#calculate id and iq in PSAT\n", + "ts_psat_4Order[\"vq\"] = TimeSeries(\"vq\", ts_psat_4Order[\"V_Bus1\"].time, vq)\n", + "\n", + "# calculate id and iq in PSAT\n", "Xd = 0.299900\n", "Xq = 0.650000\n", - "i_d = (ts_psat_4Order['eq_t'].values - ts_psat_4Order['vq'].values) / Xd\n", - "ts_psat_4Order['id'] = TimeSeries('id', ts_psat_4Order['eq_t'].time, i_d)\n", - "i_q = -(ts_psat_4Order['ed_t'].values - ts_psat_4Order['vd'].values) / Xq\n", - "ts_psat_4Order['iq'] = TimeSeries('iq', ts_psat_4Order['ed_t'].time, i_q)" + "i_d = (ts_psat_4Order[\"eq_t\"].values - ts_psat_4Order[\"vq\"].values) / Xd\n", + "ts_psat_4Order[\"id\"] = TimeSeries(\"id\", ts_psat_4Order[\"eq_t\"].time, i_d)\n", + "i_q = -(ts_psat_4Order[\"ed_t\"].values - ts_psat_4Order[\"vd\"].values) / Xq\n", + "ts_psat_4Order[\"iq\"] = TimeSeries(\"iq\", ts_psat_4Order[\"ed_t\"].time, i_q)" ] }, { @@ -213,21 +228,21 @@ "metadata": {}, "outputs": [], "source": [ - "#calculate vd and vq\n", - "angle = ts_psat_6Order['delta'].values - ts_psat_6Order['theta_bus1'].values\n", - "V_bus1 = ts_psat_6Order['V_Bus1'].values\n", + "# calculate vd and vq\n", + "angle = ts_psat_6Order[\"delta\"].values - ts_psat_6Order[\"theta_bus1\"].values\n", + "V_bus1 = ts_psat_6Order[\"V_Bus1\"].values\n", "vd = V_bus1 * np.sin(angle)\n", - "ts_psat_6Order['vd'] = TimeSeries('vd', ts_psat_6Order['V_Bus1'].time, vd)\n", + "ts_psat_6Order[\"vd\"] = TimeSeries(\"vd\", ts_psat_6Order[\"V_Bus1\"].time, vd)\n", "vq = V_bus1 * np.cos(angle)\n", - "ts_psat_6Order['vq'] = TimeSeries('vq', ts_psat_6Order['V_Bus1'].time, vq)\n", + "ts_psat_6Order[\"vq\"] = TimeSeries(\"vq\", ts_psat_6Order[\"V_Bus1\"].time, vq)\n", "\n", - "#calculate id and iq in PSAT\\n\",\n", + "# calculate id and iq in PSAT\\n\",\n", "Xd_s = 0.2299\n", "Xq_s = 0.2500\n", - "i_d = (ts_psat_6Order['eq_s'].values - ts_psat_6Order['vq'].values) / Xd_s\n", - "ts_psat_6Order['id'] = TimeSeries('id', ts_psat_6Order['eq_s'].time, i_d)\n", - "i_q = -(ts_psat_6Order['ed_s'].values - ts_psat_6Order['vd'].values) / Xq_s\n", - "ts_psat_6Order['iq'] = TimeSeries('iq', ts_psat_6Order['ed_s'].time, i_q)" + "i_d = (ts_psat_6Order[\"eq_s\"].values - ts_psat_6Order[\"vq\"].values) / Xd_s\n", + "ts_psat_6Order[\"id\"] = TimeSeries(\"id\", ts_psat_6Order[\"eq_s\"].time, i_d)\n", + "i_q = -(ts_psat_6Order[\"ed_s\"].values - ts_psat_6Order[\"vd\"].values) / Xq_s\n", + "ts_psat_6Order[\"iq\"] = TimeSeries(\"iq\", ts_psat_6Order[\"ed_s\"].time, i_q)" ] }, { @@ -248,70 +263,70 @@ }, "outputs": [], "source": [ - "#nominal values (per unit)\n", + "# nominal values (per unit)\n", "nominal_values = {}\n", - "nominal_values['Te'] = 0.540541\n", - "nominal_values['Tm'] = 0.540541\n", - "nominal_values['Edq0_0'] = 0.403062 #4th order model\n", - "nominal_values['Edq0_1'] = 0.944802 #3th and 4th order model\n", - "nominal_values['Edq0_t_0'] = 0.392200 #6 order model\n", - "nominal_values['Edq0_t_1'] = 0.946405 #6 order model\n", - "nominal_values['Edq0_s_0'] = 0.548309 #6 order model\n", - "nominal_values['Edq0_s_1'] = 0.918731 #6 order model\n", - "nominal_values['Vdq0_0'] = 0.639089\n", - "nominal_values['Vdq0_1'] = 0.833106\n", - "nominal_values['Idq0_0'] = 0.372443\n", - "nominal_values['Idq0_1'] = 0.363119\n", - "nominal_values['delta'] = 0.909230\n", - "nominal_values['w_r'] = 1.0\n", - "nominal_values['Ef'] = 1.507191\n", - "nominal_values['Vm'] = 1.05\n", - "nominal_values['Vr'] = 0.5127179\n", - "nominal_values['Vis'] = -0.1507191\n", + "nominal_values[\"Te\"] = 0.540541\n", + "nominal_values[\"Tm\"] = 0.540541\n", + "nominal_values[\"Edq0_0\"] = 0.403062 # 4th order model\n", + "nominal_values[\"Edq0_1\"] = 0.944802 # 3th and 4th order model\n", + "nominal_values[\"Edq0_t_0\"] = 0.392200 # 6 order model\n", + "nominal_values[\"Edq0_t_1\"] = 0.946405 # 6 order model\n", + "nominal_values[\"Edq0_s_0\"] = 0.548309 # 6 order model\n", + "nominal_values[\"Edq0_s_1\"] = 0.918731 # 6 order model\n", + "nominal_values[\"Vdq0_0\"] = 0.639089\n", + "nominal_values[\"Vdq0_1\"] = 0.833106\n", + "nominal_values[\"Idq0_0\"] = 0.372443\n", + "nominal_values[\"Idq0_1\"] = 0.363119\n", + "nominal_values[\"delta\"] = 0.909230\n", + "nominal_values[\"w_r\"] = 1.0\n", + "nominal_values[\"Ef\"] = 1.507191\n", + "nominal_values[\"Vm\"] = 1.05\n", + "nominal_values[\"Vr\"] = 0.5127179\n", + "nominal_values[\"Vis\"] = -0.1507191\n", "\n", "nominal_grid_voltage = 24e3\n", "\n", "#\n", "titles = {}\n", - "titles['Te'] = 'Electrical Torque'\n", - "titles['Tm'] = 'Mechanical Torque'\n", - "titles['Edq0_0'] = 'd-component of the voltage behind the transient reactance'\n", - "titles['Edq0_1'] = 'q-component of the voltage behind the transient reactance'\n", - "titles['Edq0_t_0'] = 'd-component of the voltage behind the transient reactance'\n", - "titles['Edq0_t_1'] = 'd-component of the voltage behind the transient reactance'\n", - "titles['Edq0_s_0'] = 'd-component of the voltage behind the sub-transient reactance'\n", - "titles['Edq0_s_1'] = 'd-component of the voltage behind the sub-transient reactance'\n", - "titles['Vdq0_0'] = 'd-component of the terminal voltage'\n", - "titles['Vdq0_1'] = 'q-component of the terminal voltage'\n", - "titles['Idq0_0'] = 'd-component of the terminal current'\n", - "titles['Idq0_1'] = 'q-component of the terminal current'\n", - "titles['delta'] = 'Delta'\n", - "titles['w_r'] = 'Mechanical Omega'\n", - "titles['Ef'] = 'Exiter output'\n", - "titles['Vm'] = 'Output of voltage transducer'\n", - "titles['Vr'] = 'Regulator output'\n", - "titles['Vis'] = 'Output of stablizing feedback'\n", + "titles[\"Te\"] = \"Electrical Torque\"\n", + "titles[\"Tm\"] = \"Mechanical Torque\"\n", + "titles[\"Edq0_0\"] = \"d-component of the voltage behind the transient reactance\"\n", + "titles[\"Edq0_1\"] = \"q-component of the voltage behind the transient reactance\"\n", + "titles[\"Edq0_t_0\"] = \"d-component of the voltage behind the transient reactance\"\n", + "titles[\"Edq0_t_1\"] = \"d-component of the voltage behind the transient reactance\"\n", + "titles[\"Edq0_s_0\"] = \"d-component of the voltage behind the sub-transient reactance\"\n", + "titles[\"Edq0_s_1\"] = \"d-component of the voltage behind the sub-transient reactance\"\n", + "titles[\"Vdq0_0\"] = \"d-component of the terminal voltage\"\n", + "titles[\"Vdq0_1\"] = \"q-component of the terminal voltage\"\n", + "titles[\"Idq0_0\"] = \"d-component of the terminal current\"\n", + "titles[\"Idq0_1\"] = \"q-component of the terminal current\"\n", + "titles[\"delta\"] = \"Delta\"\n", + "titles[\"w_r\"] = \"Mechanical Omega\"\n", + "titles[\"Ef\"] = \"Exiter output\"\n", + "titles[\"Vm\"] = \"Output of voltage transducer\"\n", + "titles[\"Vr\"] = \"Regulator output\"\n", + "titles[\"Vis\"] = \"Output of stablizing feedback\"\n", "\n", "#\n", "ylabels = {}\n", - "ylabels['Te'] = 'Torque (p.u.)'\n", - "ylabels['Tm'] = 'Torque (p.u.)'\n", - "ylabels['Edq0_0'] = 'Ed_t (p.u.)'\n", - "ylabels['Edq0_1'] = 'Eq_t (p.u.)'\n", - "ylabels['Edq0_t_0'] = 'Ed_t (p.u.)'\n", - "ylabels['Edq0_t_1'] = 'Eq_t (p.u.)'\n", - "ylabels['Edq0_s_0'] = 'Ed_s (p.u.)'\n", - "ylabels['Edq0_s_1'] = 'Eq_s (p.u.)'\n", - "ylabels['Vdq0_0'] = 'Vd (p.u.)'\n", - "ylabels['Vdq0_1'] = 'Vq (p.u.)'\n", - "ylabels['Idq0_0'] = 'Id (p.u.)'\n", - "ylabels['Idq0_1'] = 'Iq (p.u.)'\n", - "ylabels['delta'] = 'Delta (rad)'\n", - "ylabels['w_r'] = 'w_r (p.u.)'\n", - "ylabels['Ef'] = 'Ef (p.u.)'\n", - "ylabels['Vm'] = 'Vm (p.u.)'\n", - "ylabels['Vr'] = 'Vr (p.u.)'\n", - "ylabels['Vis'] = 'Vr2 (p.u.)'" + "ylabels[\"Te\"] = \"Torque (p.u.)\"\n", + "ylabels[\"Tm\"] = \"Torque (p.u.)\"\n", + "ylabels[\"Edq0_0\"] = \"Ed_t (p.u.)\"\n", + "ylabels[\"Edq0_1\"] = \"Eq_t (p.u.)\"\n", + "ylabels[\"Edq0_t_0\"] = \"Ed_t (p.u.)\"\n", + "ylabels[\"Edq0_t_1\"] = \"Eq_t (p.u.)\"\n", + "ylabels[\"Edq0_s_0\"] = \"Ed_s (p.u.)\"\n", + "ylabels[\"Edq0_s_1\"] = \"Eq_s (p.u.)\"\n", + "ylabels[\"Vdq0_0\"] = \"Vd (p.u.)\"\n", + "ylabels[\"Vdq0_1\"] = \"Vq (p.u.)\"\n", + "ylabels[\"Idq0_0\"] = \"Id (p.u.)\"\n", + "ylabels[\"Idq0_1\"] = \"Iq (p.u.)\"\n", + "ylabels[\"delta\"] = \"Delta (rad)\"\n", + "ylabels[\"w_r\"] = \"w_r (p.u.)\"\n", + "ylabels[\"Ef\"] = \"Ef (p.u.)\"\n", + "ylabels[\"Vm\"] = \"Vm (p.u.)\"\n", + "ylabels[\"Vr\"] = \"Vr (p.u.)\"\n", + "ylabels[\"Vis\"] = \"Vr2 (p.u.)\"" ] }, { @@ -331,76 +346,148 @@ "outputs": [], "source": [ "timestep_common = 10e-6\n", - "t_begin=0\n", - "t_end=20\n", - "begin_idx = int(t_begin/timestep_common)\n", - "end_idx= int(t_end/timestep_common)\n", + "t_begin = 0\n", + "t_end = 20\n", + "begin_idx = int(t_begin / timestep_common)\n", + "end_idx = int(t_end / timestep_common)\n", "\n", - "#plot Results\n", + "# plot Results\n", "width = 12\n", "height = 4\n", "\n", - "def plot_variable(title, varname_dpsim, varname_psat, ts_dpsim, ts_psat, nominal_values, ylabels):\n", + "\n", + "def plot_variable(\n", + " title, varname_dpsim, varname_psat, ts_dpsim, ts_psat, nominal_values, ylabels\n", + "):\n", " fig1 = plt.figure(figsize=(width, height))\n", - " plt.plot(ts_dpsim[varname_dpsim].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim[varname_dpsim].interpolate(timestep_common).values[begin_idx:end_idx], label='DPSim')\n", - " plt.plot(ts_psat[varname_psat].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx], '--', label='PSAT')\n", - " #plt.plot(ts_psat_3Order_[varname_psat].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat_3Order_[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx], '--', label='PSAT')\n", - " plt.legend(loc='lower right')\n", - " plt.xlabel('time (s)')\n", + " plt.plot(\n", + " ts_dpsim[varname_dpsim].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim[varname_dpsim].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=\"DPSim\",\n", + " )\n", + " plt.plot(\n", + " ts_psat[varname_psat].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " \"--\",\n", + " label=\"PSAT\",\n", + " )\n", + " # plt.plot(ts_psat_3Order_[varname_psat].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat_3Order_[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx], '--', label='PSAT')\n", + " plt.legend(loc=\"lower right\")\n", + " plt.xlabel(\"time (s)\")\n", " plt.ylabel(ylabels[varname_dpsim])\n", " plt.grid()\n", " plt.xlim([0, 10])\n", " plt.show\n", - " \n", - " #calculate RMSE\n", + "\n", + " # calculate RMSE\n", " nom_value = nominal_values[varname_dpsim]\n", - " rmse = ts_dpsim[varname_dpsim].rmse(ts_dpsim[varname_dpsim].interpolate(timestep_common), ts_psat[varname_psat].interpolate(timestep_common))\n", - " print('RMSE {:s} = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) '.format(varname_dpsim, rmse, rmse/nom_value*100, nom_value))\n", - " \n", - " return rmse/nom_value*100\n", - "\n", - "def plot_node_volt_abs(varname_dpsim, varname_psat, ts_dpsim, ts_psat, nominal_voltage, ylabels):\n", - " \n", - " #convert dpsim voltage to magnitude value and per-unit for comparison with psat\n", - " ts_dpsim_abs_pu = TimeSeries(varname_dpsim+'_abs_pu', ts_dpsim[varname_dpsim].interpolate(timestep_common).time, ts_dpsim[varname_dpsim].interpolate(timestep_common).abs().values/nominal_voltage)\n", - " \n", + " rmse = ts_dpsim[varname_dpsim].rmse(\n", + " ts_dpsim[varname_dpsim].interpolate(timestep_common),\n", + " ts_psat[varname_psat].interpolate(timestep_common),\n", + " )\n", + " print(\n", + " \"RMSE {:s} = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) \".format(\n", + " varname_dpsim, rmse, rmse / nom_value * 100, nom_value\n", + " )\n", + " )\n", + "\n", + " return rmse / nom_value * 100\n", + "\n", + "\n", + "def plot_node_volt_abs(\n", + " varname_dpsim, varname_psat, ts_dpsim, ts_psat, nominal_voltage, ylabels\n", + "):\n", + " # convert dpsim voltage to magnitude value and per-unit for comparison with psat\n", + " ts_dpsim_abs_pu = TimeSeries(\n", + " varname_dpsim + \"_abs_pu\",\n", + " ts_dpsim[varname_dpsim].interpolate(timestep_common).time,\n", + " ts_dpsim[varname_dpsim].interpolate(timestep_common).abs().values\n", + " / nominal_voltage,\n", + " )\n", + "\n", " fig1 = plt.figure(figsize=(width, height))\n", - " plt.plot(ts_dpsim_abs_pu.time[begin_idx:end_idx], ts_dpsim_abs_pu.values[begin_idx:end_idx], label='DPSim')\n", - " plt.plot(ts_psat[varname_psat].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx], '--', label='PSAT')\n", - " plt.legend(loc='lower right')\n", - " plt.xlabel('time (s)')\n", + " plt.plot(\n", + " ts_dpsim_abs_pu.time[begin_idx:end_idx],\n", + " ts_dpsim_abs_pu.values[begin_idx:end_idx],\n", + " label=\"DPSim\",\n", + " )\n", + " plt.plot(\n", + " ts_psat[varname_psat].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " \"--\",\n", + " label=\"PSAT\",\n", + " )\n", + " plt.legend(loc=\"lower right\")\n", + " plt.xlabel(\"time (s)\")\n", " plt.show\n", - " \n", - " #calculate RMSE\n", - " rmse = ts_dpsim[varname_dpsim].rmse(ts_dpsim_abs_pu, ts_psat[varname_psat].interpolate(timestep_common))\n", - " print('RMSE {:s} = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) '.format(varname_dpsim, rmse, rmse/1.0*100, 1.0))\n", - " \n", - " return rmse/1.0*100\n", - "\n", - "\n", - "def plot_node_volt_angle(varname_dpsim, varname_psat, ts_dpsim, ts_psat, nominal_voltage, ylabels):\n", - " #limit rmse to post-fault evaluation\n", - " t_post_begin=1.1\n", - " t_post_end=20\n", - " begin_post_idx = int(t_post_begin/timestep_common)\n", - " end_post_idx= int(t_post_end/timestep_common)\n", - " \n", - " #convert psat angle to deg and in range from\n", - " ts_psat_deg = TimeSeries(varname_psat+'_deg', ts_psat[varname_psat].interpolate(timestep_common).time, ts_psat[varname_psat].interpolate(timestep_common).values/np.pi*180)\n", - " \n", + "\n", + " # calculate RMSE\n", + " rmse = ts_dpsim[varname_dpsim].rmse(\n", + " ts_dpsim_abs_pu, ts_psat[varname_psat].interpolate(timestep_common)\n", + " )\n", + " print(\n", + " \"RMSE {:s} = {:.6f} (pu), which is {:.3f}% of the nominal value = {:.3f} (pu) \".format(\n", + " varname_dpsim, rmse, rmse / 1.0 * 100, 1.0\n", + " )\n", + " )\n", + "\n", + " return rmse / 1.0 * 100\n", + "\n", + "\n", + "def plot_node_volt_angle(\n", + " varname_dpsim, varname_psat, ts_dpsim, ts_psat, nominal_voltage, ylabels\n", + "):\n", + " # limit rmse to post-fault evaluation\n", + " t_post_begin = 1.1\n", + " t_post_end = 20\n", + " begin_post_idx = int(t_post_begin / timestep_common)\n", + " end_post_idx = int(t_post_end / timestep_common)\n", + "\n", + " # convert psat angle to deg and in range from\n", + " ts_psat_deg = TimeSeries(\n", + " varname_psat + \"_deg\",\n", + " ts_psat[varname_psat].interpolate(timestep_common).time,\n", + " ts_psat[varname_psat].interpolate(timestep_common).values / np.pi * 180,\n", + " )\n", + "\n", " fig2 = plt.figure(figsize=(width, height))\n", - " plt.plot(ts_dpsim[varname_dpsim].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim[varname_dpsim].interpolate(timestep_common).phase().values[begin_idx:end_idx], label='DPSim')\n", - " plt.plot(ts_psat_deg.time[begin_idx:end_idx], ts_psat_deg.values[begin_idx:end_idx], '--', label='PSAT')\n", - " plt.legend(loc='lower right')\n", - " plt.xlabel('time (s)')\n", + " plt.plot(\n", + " ts_dpsim[varname_dpsim].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim[varname_dpsim]\n", + " .interpolate(timestep_common)\n", + " .phase()\n", + " .values[begin_idx:end_idx],\n", + " label=\"DPSim\",\n", + " )\n", + " plt.plot(\n", + " ts_psat_deg.time[begin_idx:end_idx],\n", + " ts_psat_deg.values[begin_idx:end_idx],\n", + " \"--\",\n", + " label=\"PSAT\",\n", + " )\n", + " plt.legend(loc=\"lower right\")\n", + " plt.xlabel(\"time (s)\")\n", " plt.show\n", - " \n", - " #calculate RMSE\n", - " ts_dpsim_deg_post = TimeSeries(varname_dpsim+'_deg_post', ts_dpsim[varname_dpsim].interpolate(timestep_common).time[begin_post_idx:end_post_idx], ts_dpsim[varname_dpsim].interpolate(timestep_common).phase().values[begin_post_idx:end_post_idx])\n", - " ts_psat_deg_post = TimeSeries(varname_psat+'_deg_post', ts_psat_deg.time[begin_post_idx:end_post_idx], ts_psat_deg.values[begin_post_idx:end_post_idx])\n", + "\n", + " # calculate RMSE\n", + " ts_dpsim_deg_post = TimeSeries(\n", + " varname_dpsim + \"_deg_post\",\n", + " ts_dpsim[varname_dpsim]\n", + " .interpolate(timestep_common)\n", + " .time[begin_post_idx:end_post_idx],\n", + " ts_dpsim[varname_dpsim]\n", + " .interpolate(timestep_common)\n", + " .phase()\n", + " .values[begin_post_idx:end_post_idx],\n", + " )\n", + " ts_psat_deg_post = TimeSeries(\n", + " varname_psat + \"_deg_post\",\n", + " ts_psat_deg.time[begin_post_idx:end_post_idx],\n", + " ts_psat_deg.values[begin_post_idx:end_post_idx],\n", + " )\n", " rmse = ts_dpsim[varname_dpsim].rmse(ts_dpsim_deg_post, ts_psat_deg_post)\n", - " print('RMSE Post-Fault {:s} = {:.6f} (deg)'.format(varname_dpsim, rmse))\n", - " \n", + " print(\"RMSE Post-Fault {:s} = {:.6f} (deg)\".format(varname_dpsim, rmse))\n", + "\n", " return rmse" ] }, @@ -432,7 +519,15 @@ "varname_dpsim = \"Te\"\n", "varname_psat = \"p\"\n", "\n", - "rmse_torque = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_torque = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -454,7 +549,15 @@ "varname_dpsim = \"Ef\"\n", "varname_psat = \"vf\"\n", "\n", - "rmse_ef = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_ef = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -476,7 +579,15 @@ "varname_dpsim = \"Edq0_1\"\n", "varname_psat = \"eq_t\"\n", "\n", - "rmse_eq = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_eq = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -498,7 +609,15 @@ "varname_dpsim = \"Vdq0_0\"\n", "varname_psat = \"vd\"\n", "\n", - "rmse_vd = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_vd = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -520,7 +639,15 @@ "varname_dpsim = \"Vdq0_1\"\n", "varname_psat = \"vq\"\n", "\n", - "rmse_vq = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_vq = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -542,9 +669,17 @@ "varname_dpsim = \"Idq0_0\"\n", "varname_psat = \"id\"\n", "\n", - "rmse_id = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)\n", - "#plt.plot(ts_dpsim_3Order[varname_dpsim].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat_3Order[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx]- ts_dpsim_3Order[varname_dpsim].interpolate(timestep_common).values[begin_idx:end_idx])\n", - "#plt.ylim([0, 0.02])" + "rmse_id = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")\n", + "# plt.plot(ts_dpsim_3Order[varname_dpsim].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat_3Order[varname_psat].interpolate(timestep_common).values[begin_idx:end_idx]- ts_dpsim_3Order[varname_dpsim].interpolate(timestep_common).values[begin_idx:end_idx])\n", + "# plt.ylim([0, 0.02])" ] }, { @@ -566,7 +701,15 @@ "varname_dpsim = \"Idq0_1\"\n", "varname_psat = \"iq\"\n", "\n", - "rmse_iq = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_iq = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -588,7 +731,15 @@ "varname_dpsim = \"delta\"\n", "varname_psat = \"delta\"\n", "\n", - "rmse_delta = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_delta = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -610,7 +761,15 @@ "varname_dpsim = \"w_r\"\n", "varname_psat = \"omega\"\n", "\n", - "rmse_omega = plot_variable(titles, varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_values, ylabels)" + "rmse_omega = plot_variable(\n", + " titles,\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_values,\n", + " ylabels,\n", + ")" ] }, { @@ -632,7 +791,14 @@ "varname_dpsim = \"v1\"\n", "varname_psat = \"V_Bus1\"\n", "\n", - "rmse_v1_abs = plot_node_volt_abs(varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_grid_voltage, ylabels)" + "rmse_v1_abs = plot_node_volt_abs(\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_grid_voltage,\n", + " ylabels,\n", + ")" ] }, { @@ -645,7 +811,14 @@ "varname_dpsim = \"v1\"\n", "varname_psat = \"theta_bus1\"\n", "\n", - "rmse_v1_angle = plot_node_volt_angle(varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_grid_voltage, ylabels)" + "rmse_v1_angle = plot_node_volt_angle(\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_grid_voltage,\n", + " ylabels,\n", + ")" ] }, { @@ -658,7 +831,14 @@ "varname_dpsim = \"v2\"\n", "varname_psat = \"V_Bus3\"\n", "\n", - "rmse_v2_abs = plot_node_volt_abs(varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_grid_voltage, ylabels)" + "rmse_v2_abs = plot_node_volt_abs(\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_grid_voltage,\n", + " ylabels,\n", + ")" ] }, { @@ -671,7 +851,14 @@ "varname_dpsim = \"v2\"\n", "varname_psat = \"theta_bus3\"\n", "\n", - "rmse_v2_angle = plot_node_volt_angle(varname_dpsim, varname_psat, ts_dpsim_3Order, ts_psat_3Order, nominal_grid_voltage, ylabels)" + "rmse_v2_angle = plot_node_volt_angle(\n", + " varname_dpsim,\n", + " varname_psat,\n", + " ts_dpsim_3Order,\n", + " ts_psat_3Order,\n", + " nominal_grid_voltage,\n", + " ylabels,\n", + ")" ] }, { @@ -690,24 +877,24 @@ "metadata": {}, "outputs": [], "source": [ - "tol = 1.5 # %\n", - "tol_id = 7 # %\n", - "tol_deg_v1 = 0.2 # deg\n", - "tol_deg_v2 = 1e-12 # deg\n", + "tol = 1.5 # %\n", + "tol_id = 7 # %\n", + "tol_deg_v1 = 0.2 # deg\n", + "tol_deg_v2 = 1e-12 # deg\n", "\n", - "assert(rmse_torque 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", - " result_list.append({'timestep': ts_idx, 'load': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"load\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_ode = pd.DataFrame(result_list)" ], "outputs": [], @@ -486,20 +583,24 @@ "source": [ "loadstep = 8\n", "timestep = 1\n", - "curr = pd_emt_ode.query('timestep=='+str(timestep)+' and load=='+str(loadstep))['values'].values[0]\n", - "plt.plot(curr['i_gen_0'].time, curr['i_gen_0'].values, color = '#939393ff')\n", - "plt.plot(curr['i_gen_1'].time, curr['i_gen_1'].values, color = '#939393ff')\n", - "plt.plot(curr['i_gen_2'].time, curr['i_gen_2'].values, color = '#939393ff')\n", + "curr = pd_emt_ode.query(\"timestep==\" + str(timestep) + \" and load==\" + str(loadstep))[\n", + " \"values\"\n", + "].values[0]\n", + "plt.plot(curr[\"i_gen_0\"].time, curr[\"i_gen_0\"].values, color=\"#939393ff\")\n", + "plt.plot(curr[\"i_gen_1\"].time, curr[\"i_gen_1\"].values, color=\"#939393ff\")\n", + "plt.plot(curr[\"i_gen_2\"].time, curr[\"i_gen_2\"].values, color=\"#939393ff\")\n", "\n", "timestep = 8\n", - "curr = pd_emt_ode.query('timestep=='+str(timestep)+' and load=='+str(loadstep))['values'].values[0]\n", - "plt.plot(curr['i_gen_0_intpl'].time, curr['i_gen_0_intpl'].values, linestyle='-.')\n", - "plt.plot(curr['i_gen_1_intpl'].time, curr['i_gen_1_intpl'].values, linestyle='-.')\n", - "plt.plot(curr['i_gen_2_intpl'].time, curr['i_gen_2_intpl'].values, linestyle='-.')\n", - "\n", - "#plt.xlim([0.19,0.21])\n", - "plt.xlim([0.09,0.12])\n", - "#plt.ylim([-15000,15000])" + "curr = pd_emt_ode.query(\"timestep==\" + str(timestep) + \" and load==\" + str(loadstep))[\n", + " \"values\"\n", + "].values[0]\n", + "plt.plot(curr[\"i_gen_0_intpl\"].time, curr[\"i_gen_0_intpl\"].values, linestyle=\"-.\")\n", + "plt.plot(curr[\"i_gen_1_intpl\"].time, curr[\"i_gen_1_intpl\"].values, linestyle=\"-.\")\n", + "plt.plot(curr[\"i_gen_2_intpl\"].time, curr[\"i_gen_2_intpl\"].values, linestyle=\"-.\")\n", + "\n", + "# plt.xlim([0.19,0.21])\n", + "plt.xlim([0.09, 0.12])\n", + "# plt.ylim([-15000,15000])" ], "outputs": [], "metadata": {} @@ -510,17 +611,32 @@ "source": [ "loadstep = 2\n", "timestep = 2\n", - "curr = pd_emt_ode.query('timestep=='+str(1)+' and load=='+str(loadstep))['values'].values[0]\n", - "curr_ts = pd_emt_ode.query('timestep=='+str(timestep)+' and load=='+str(loadstep))['values'].values[0]\n", - "min_length = 3000 #min(curr['i_gen_0'].values.shape, curr_ts['i_gen_0_intpl'].values.shape)[0]\n", - "plt.plot(curr['i_gen_0'].time[:min_length], curr['i_gen_0'].values[:min_length] - curr_ts['i_gen_0_intpl'].values[:min_length])\n", - "plt.plot(curr['i_gen_1'].time[:min_length], curr['i_gen_1'].values[:min_length] - curr_ts['i_gen_1_intpl'].values[:min_length])\n", - "plt.plot(curr['i_gen_2'].time[:min_length], curr['i_gen_2'].values[:min_length] - curr_ts['i_gen_2_intpl'].values[:min_length])\n", - "\n", - "#plt.xlim([0.09,0.15])\n", - "#plt.ylim([-2000,2000])\n", - "#plt.xlim([0.19,0.21])\n", - "#plt.ylim([-15000,15000])" + "curr = pd_emt_ode.query(\"timestep==\" + str(1) + \" and load==\" + str(loadstep))[\n", + " \"values\"\n", + "].values[0]\n", + "curr_ts = pd_emt_ode.query(\n", + " \"timestep==\" + str(timestep) + \" and load==\" + str(loadstep)\n", + ")[\"values\"].values[0]\n", + "min_length = (\n", + " 3000 # min(curr['i_gen_0'].values.shape, curr_ts['i_gen_0_intpl'].values.shape)[0]\n", + ")\n", + "plt.plot(\n", + " curr[\"i_gen_0\"].time[:min_length],\n", + " curr[\"i_gen_0\"].values[:min_length] - curr_ts[\"i_gen_0_intpl\"].values[:min_length],\n", + ")\n", + "plt.plot(\n", + " curr[\"i_gen_1\"].time[:min_length],\n", + " curr[\"i_gen_1\"].values[:min_length] - curr_ts[\"i_gen_1_intpl\"].values[:min_length],\n", + ")\n", + "plt.plot(\n", + " curr[\"i_gen_2\"].time[:min_length],\n", + " curr[\"i_gen_2\"].values[:min_length] - curr_ts[\"i_gen_2_intpl\"].values[:min_length],\n", + ")\n", + "\n", + "# plt.xlim([0.09,0.15])\n", + "# plt.ylim([-2000,2000])\n", + "# plt.xlim([0.19,0.21])\n", + "# plt.ylim([-15000,15000])" ], "outputs": [], "metadata": {} @@ -531,6 +647,7 @@ "source": [ "import numpy as np\n", "\n", + "\n", "def calc_dpsim_variable_timestep_mae(ref, test_list):\n", " # find the minimum number of time steps available in the list of timeseries results\n", " min_length = ref.values.shape[0]\n", @@ -540,17 +657,19 @@ " min_length = 3000\n", " # calculate maximum amplitude of EMT reference signal to normalize error\n", " max_amp = np.max(np.abs(ref.values[:min_length]))\n", - " print('max. amplitude: ' +str(max_amp))\n", + " print(\"max. amplitude: \" + str(max_amp))\n", " # Calculate difference for each timeseries with respect to the 50µs reference\n", " diff_list = []\n", " for test in test_list:\n", - " diff_list.append( (test.values[:min_length] - ref.values[:min_length]) )#/ max_amp )\n", + " diff_list.append(\n", + " (test.values[:min_length] - ref.values[:min_length])\n", + " ) # / max_amp )\n", "\n", " # calculate mean absolute error\n", " mae = []\n", " for diff in diff_list:\n", - " mae.append( np.sum(np.abs(diff)) / min_length )\n", - " \n", + " mae.append(np.sum(np.abs(diff)) / min_length)\n", + "\n", " return mae, diff_list" ], "outputs": [], @@ -562,16 +681,18 @@ "source": [ "mae_emt_ode_list = []\n", "\n", - "for load_idx in range(0,11): \n", - " pd_test_list = pd_emt_ode.query('timestep > 1 and load=='+str(load_idx))\n", + "for load_idx in range(0, 11):\n", + " pd_test_list = pd_emt_ode.query(\"timestep > 1 and load==\" + str(load_idx))\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['i_gen_0_intpl'])\n", - " \n", - " ref = pd_emt_ode.query('timestep == 1 and load=='+str(load_idx)).iloc[0]['values']['i_gen_0']\n", + " test_list.append(row[\"values\"][\"i_gen_0_intpl\"])\n", + "\n", + " ref = pd_emt_ode.query(\"timestep == 1 and load==\" + str(load_idx)).iloc[0][\n", + " \"values\"\n", + " ][\"i_gen_0\"]\n", " mae_emt_ode, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", " mae_emt_ode_list.append(mae_emt_ode)\n", - " #print(mae_emt_ode)" + " # print(mae_emt_ode)" ], "outputs": [], "metadata": {} @@ -580,20 +701,20 @@ "cell_type": "code", "execution_count": null, "source": [ - "timesteps = np.arange(2,21)*0.00005\n", - "for load_idx in range(1,11,2): \n", - " plt.plot(timesteps, mae_emt_ode_list[load_idx], 'o-', label='step '+str(load_idx))\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "for load_idx in range(1, 11, 2):\n", + " plt.plot(timesteps, mae_emt_ode_list[load_idx], \"o-\", label=\"step \" + str(load_idx))\n", "plt.legend()\n", - "#plt.ylim([-0.01,0.1])\n", - "plt.ylim([0,3000])\n", - "plt.xlim([0,0.0009])\n", + "# plt.ylim([-0.01,0.1])\n", + "plt.ylim([0, 3000])\n", + "plt.xlim([0, 0.0009])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean absolute error current (A)')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean absolute error current (A)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('emt_ode_syngen_mae.pdf')" + "plt.savefig(\"emt_ode_syngen_mae.pdf\")" ], "outputs": [], "metadata": {} @@ -611,18 +732,19 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(0,11):\n", - " log_dir = 'logs/'\n", - " log_name = log_dir+'DP_SynGenDq7odODE_T' + str(ts_idx) + '_L' + str(load_idx) + '/' \\\n", - " 'DP_SynGenDq7odODE_T' + str(ts_idx) + '_L' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(0, 11):\n", + " log_dir = \"logs/\"\n", + " log_name = log_dir + \"DP_SynGenDq7odODE_T\" + str(ts_idx) + \"_L\" + str(\n", + " load_idx\n", + " ) + \"/\" \"DP_SynGenDq7odODE_T\" + str(ts_idx) + \"_L\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 60)\n", - " result_list.append({'timestep': ts_idx, 'load': load_idx, 'values': ts_curr}) \n", - " \n", + " result_list.append({\"timestep\": ts_idx, \"load\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_dp_ode = pd.DataFrame(result_list)" ], "outputs": [], @@ -643,16 +765,18 @@ "source": [ "mae_dp_ode_list = []\n", "\n", - "for load_idx in range(0,11): \n", - " pd_test_list = pd_dp_ode.query('timestep > 1 and load=='+str(load_idx))\n", + "for load_idx in range(0, 11):\n", + " pd_test_list = pd_dp_ode.query(\"timestep > 1 and load==\" + str(load_idx))\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['i_gen_0_intpl_shift'])\n", - " \n", - " ref = pd_dp_ode.query('timestep == 1 and load=='+str(load_idx)).iloc[0]['values']['i_gen_0_shift']\n", + " test_list.append(row[\"values\"][\"i_gen_0_intpl_shift\"])\n", + "\n", + " ref = pd_dp_ode.query(\"timestep == 1 and load==\" + str(load_idx)).iloc[0][\"values\"][\n", + " \"i_gen_0_shift\"\n", + " ]\n", " mae, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", - " #print(mae)\n", - " mae_dp_ode_list.append(mae) " + " # print(mae)\n", + " mae_dp_ode_list.append(mae)" ], "outputs": [], "metadata": {} @@ -661,20 +785,20 @@ "cell_type": "code", "execution_count": null, "source": [ - "timesteps = np.arange(2,21)*0.00005\n", - "for load_idx in range(1,11,2): \n", - " plt.plot(timesteps, mae_dp_ode_list[load_idx], 'o-', label='load '+str(load_idx))\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "for load_idx in range(1, 11, 2):\n", + " plt.plot(timesteps, mae_dp_ode_list[load_idx], \"o-\", label=\"load \" + str(load_idx))\n", "plt.legend()\n", - "#plt.ylim([-0.01,0.3])\n", - "plt.ylim([0,200])\n", - "plt.xlim([0,0.0009])\n", + "# plt.ylim([-0.01,0.3])\n", + "plt.ylim([0, 200])\n", + "plt.xlim([0, 0.0009])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean absolute error current (A)')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean absolute error current (A)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_ode_syngen_mae.pdf')" + "plt.savefig(\"dp_ode_syngen_mae.pdf\")" ], "outputs": [], "metadata": {} @@ -692,17 +816,18 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(0,11):\n", - " log_dir = 'logs/'\n", - " log_name = 'logs/EMT_SynGenDq7odTrapez_T' + str(ts_idx) + '_L' + str(load_idx) + '/' \\\n", - " 'EMT_SynGenDq7odTrapez_T' + str(ts_idx) + '_L' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(0, 11):\n", + " log_dir = \"logs/\"\n", + " log_name = \"logs/EMT_SynGenDq7odTrapez_T\" + str(ts_idx) + \"_L\" + str(\n", + " load_idx\n", + " ) + \"/\" \"EMT_SynGenDq7odTrapez_T\" + str(ts_idx) + \"_L\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", - " ts_curr = ts.interpolate_list(ts_curr, 0.00005) \n", - " result_list.append({'timestep': ts_idx, 'load': load_idx, 'values': ts_curr}) \n", - " \n", + " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", + " result_list.append({\"timestep\": ts_idx, \"load\": load_idx, \"values\": ts_curr})\n", + "\n", "pd_emt_trapez = pd.DataFrame(result_list)" ], "outputs": [], @@ -722,16 +847,18 @@ "execution_count": null, "source": [ "mae_emt_trapez_list = []\n", - "for load_idx in range(0,11): \n", - " pd_test_list = pd_emt_trapez.query('timestep > 1 and load=='+str(load_idx))\n", + "for load_idx in range(0, 11):\n", + " pd_test_list = pd_emt_trapez.query(\"timestep > 1 and load==\" + str(load_idx))\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['i_gen_0_intpl'])\n", - " \n", - " ref = pd_emt_trapez.query('timestep == 1 and load=='+str(load_idx)).iloc[0]['values']['i_gen_0']\n", + " test_list.append(row[\"values\"][\"i_gen_0_intpl\"])\n", + "\n", + " ref = pd_emt_trapez.query(\"timestep == 1 and load==\" + str(load_idx)).iloc[0][\n", + " \"values\"\n", + " ][\"i_gen_0\"]\n", " mae, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", - " #print(mae)\n", - " mae_emt_trapez_list.append(mae) " + " # print(mae)\n", + " mae_emt_trapez_list.append(mae)" ], "outputs": [], "metadata": {} @@ -740,20 +867,22 @@ "cell_type": "code", "execution_count": null, "source": [ - "timesteps = np.arange(2,21)*0.00005\n", - "for load_idx in range(1,11,2): \n", - " plt.plot(timesteps, mae_emt_trapez_list[load_idx], 'o-', label='load '+str(load_idx))\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "for load_idx in range(1, 11, 2):\n", + " plt.plot(\n", + " timesteps, mae_emt_trapez_list[load_idx], \"o-\", label=\"load \" + str(load_idx)\n", + " )\n", "plt.legend()\n", - "#plt.ylim([-0.01,0.3])\n", - "plt.ylim([0,3000])\n", - "plt.xlim([0,0.0009])\n", + "# plt.ylim([-0.01,0.3])\n", + "plt.ylim([0, 3000])\n", + "plt.xlim([0, 0.0009])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean absolute error current (A)')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean absolute error current (A)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('dp_trpz_syngen_mae.pdf')" + "plt.savefig(\"dp_trpz_syngen_mae.pdf\")" ], "outputs": [], "metadata": {} @@ -771,17 +900,18 @@ "source": [ "%%capture\n", "result_list = []\n", - "for ts_idx in range(1,21):\n", - " for load_idx in range(0,11):\n", - " log_dir = '../../../logs/'\n", - " log_name = log_dir+'DP_SynGenDq7odTrapez_T' + str(ts_idx) + '_L' + str(load_idx) + '/' \\\n", - " 'DP_SynGenDq7odTrapez_T' + str(ts_idx) + '_L' + str(load_idx)\n", - " \n", - " ts_curr = rt.read_timeseries_dpsim(log_name + '.csv')\n", + "for ts_idx in range(1, 21):\n", + " for load_idx in range(0, 11):\n", + " log_dir = \"../../../logs/\"\n", + " log_name = log_dir + \"DP_SynGenDq7odTrapez_T\" + str(ts_idx) + \"_L\" + str(\n", + " load_idx\n", + " ) + \"/\" \"DP_SynGenDq7odTrapez_T\" + str(ts_idx) + \"_L\" + str(load_idx)\n", + "\n", + " ts_curr = rt.read_timeseries_dpsim(log_name + \".csv\")\n", " if ts_idx > 1:\n", - " ts_curr = ts.interpolate_list(ts_curr, 0.00005) \n", + " ts_curr = ts.interpolate_list(ts_curr, 0.00005)\n", " ts_curr = ts.frequency_shift_list(ts_curr, 60)\n", - " result_list.append({'timestep': ts_idx, 'load': load_idx, 'values': ts_curr}) \n", + " result_list.append({\"timestep\": ts_idx, \"load\": load_idx, \"values\": ts_curr})\n", "\n", "pd_dp_trapez = pd.DataFrame(result_list)" ], @@ -802,16 +932,18 @@ "execution_count": null, "source": [ "mae_dp_trapez_list = []\n", - "for load_idx in range(0,11): \n", - " pd_test_list = pd_dp_trapez.query('timestep > 1 and load=='+str(load_idx))\n", + "for load_idx in range(0, 11):\n", + " pd_test_list = pd_dp_trapez.query(\"timestep > 1 and load==\" + str(load_idx))\n", " test_list = []\n", " for index, row in pd_test_list.iterrows():\n", - " test_list.append(row['values']['i_gen_0_intpl_shift'])\n", - " \n", - " ref = pd_dp_trapez.query('timestep == 1 and load=='+str(load_idx)).iloc[0]['values']['i_gen_0_shift']\n", + " test_list.append(row[\"values\"][\"i_gen_0_intpl_shift\"])\n", + "\n", + " ref = pd_dp_trapez.query(\"timestep == 1 and load==\" + str(load_idx)).iloc[0][\n", + " \"values\"\n", + " ][\"i_gen_0_shift\"]\n", " mae, diff_list = calc_dpsim_variable_timestep_mae(ref, test_list)\n", - " #print(mae)\n", - " mae_dp_trapez_list.append(mae) " + " # print(mae)\n", + " mae_dp_trapez_list.append(mae)" ], "outputs": [], "metadata": {} @@ -820,20 +952,22 @@ "cell_type": "code", "execution_count": null, "source": [ - "timesteps = np.arange(2,21)*0.00005\n", - "for load_idx in range(1,11,2): \n", - " plt.plot(timesteps, mae_dp_trapez_list[load_idx], 'o-', label='load '+str(load_idx))\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "for load_idx in range(1, 11, 2):\n", + " plt.plot(\n", + " timesteps, mae_dp_trapez_list[load_idx], \"o-\", label=\"load \" + str(load_idx)\n", + " )\n", "plt.legend()\n", - "#plt.ylim([-0.01,0.3])\n", - "plt.xlim([0,0.0009])\n", - "plt.ylim([0,200])\n", + "# plt.ylim([-0.01,0.3])\n", + "plt.xlim([0, 0.0009])\n", + "plt.ylim([0, 200])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean absolute error current (A)')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean absolute error current (A)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('emt_trpz_syngen_mae.pdf')" + "plt.savefig(\"emt_trpz_syngen_mae.pdf\")" ], "outputs": [], "metadata": {} @@ -842,20 +976,22 @@ "cell_type": "code", "execution_count": null, "source": [ - "timesteps = np.arange(2,21)*0.00005\n", - "for load_idx in range(1,11,2): \n", - " plt.plot(timesteps, mae_dp_trapez_list[load_idx], 'o-', label='load '+str(load_idx))\n", + "timesteps = np.arange(2, 21) * 0.00005\n", + "for load_idx in range(1, 11, 2):\n", + " plt.plot(\n", + " timesteps, mae_dp_trapez_list[load_idx], \"o-\", label=\"load \" + str(load_idx)\n", + " )\n", "plt.legend()\n", - "#plt.ylim([-0.01,0.3])\n", - "#plt.xlim([0,0.0009])\n", - "#plt.ylim([0,200])\n", + "# plt.ylim([-0.01,0.3])\n", + "# plt.xlim([0,0.0009])\n", + "# plt.ylim([0,200])\n", "\n", - "plt.xlabel('timestep (s)')\n", - "plt.ylabel('mean absolute error current (A)')\n", + "plt.xlabel(\"timestep (s)\")\n", + "plt.ylabel(\"mean absolute error current (A)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('emt_trpz_syngen_mae.pdf')" + "plt.savefig(\"emt_trpz_syngen_mae.pdf\")" ], "outputs": [], "metadata": {} @@ -865,16 +1001,26 @@ "execution_count": null, "source": [ "loadstep = 5\n", - "curr = pd_dp_trapez.query('timestep=='+str(1)+' and load=='+str(loadstep))['values'].values[0]\n", - "plt.plot(curr['i_gen_0_shift'].time, curr['i_gen_0_shift'].values, color = '#939393ff')\n", - "plt.plot(curr['i_gen_1_shift'].time, curr['i_gen_1_shift'].values, color = '#939393ff')\n", - "plt.plot(curr['i_gen_2_shift'].time, curr['i_gen_2_shift'].values, color = '#939393ff')\n", + "curr = pd_dp_trapez.query(\"timestep==\" + str(1) + \" and load==\" + str(loadstep))[\n", + " \"values\"\n", + "].values[0]\n", + "plt.plot(curr[\"i_gen_0_shift\"].time, curr[\"i_gen_0_shift\"].values, color=\"#939393ff\")\n", + "plt.plot(curr[\"i_gen_1_shift\"].time, curr[\"i_gen_1_shift\"].values, color=\"#939393ff\")\n", + "plt.plot(curr[\"i_gen_2_shift\"].time, curr[\"i_gen_2_shift\"].values, color=\"#939393ff\")\n", "\n", "timestep = 12\n", - "curr = pd_dp_trapez.query('timestep=='+str(timestep)+' and load=='+str(loadstep))['values'].values[0]\n", - "plt.plot(curr['i_gen_0_intpl_shift'].time, curr['i_gen_0_intpl_shift'].values, linestyle='-.')\n", - "plt.plot(curr['i_gen_1_intpl_shift'].time, curr['i_gen_1_intpl_shift'].values, linestyle='-.')\n", - "plt.plot(curr['i_gen_2_intpl_shift'].time, curr['i_gen_2_intpl_shift'].values, linestyle='-.')" + "curr = pd_dp_trapez.query(\"timestep==\" + str(timestep) + \" and load==\" + str(loadstep))[\n", + " \"values\"\n", + "].values[0]\n", + "plt.plot(\n", + " curr[\"i_gen_0_intpl_shift\"].time, curr[\"i_gen_0_intpl_shift\"].values, linestyle=\"-.\"\n", + ")\n", + "plt.plot(\n", + " curr[\"i_gen_1_intpl_shift\"].time, curr[\"i_gen_1_intpl_shift\"].values, linestyle=\"-.\"\n", + ")\n", + "plt.plot(\n", + " curr[\"i_gen_2_intpl_shift\"].time, curr[\"i_gen_2_intpl_shift\"].values, linestyle=\"-.\"\n", + ")" ], "outputs": [], "metadata": {} @@ -904,4 +1050,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/examples/Notebooks/Components/SynGenDq7od_SteadyState_DP_EMT.ipynb b/examples/Notebooks/Components/SynGenDq7od_SteadyState_DP_EMT.ipynb index d100b71b0d..99f4c98950 100644 --- a/examples/Notebooks/Components/SynGenDq7od_SteadyState_DP_EMT.ipynb +++ b/examples/Notebooks/Components/SynGenDq7od_SteadyState_DP_EMT.ipynb @@ -43,8 +43,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'DP_SynGenDq7odODE_SteadyState'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_SynGenDq7odODE_SteadyState\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -79,22 +79,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.dp.ph3.SynchronGeneratorDQODE('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.dp.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.dp.ph3.SynchronGeneratorDQODE(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.dp.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.dp.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.dp.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -104,10 +127,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_load', 'i_intf', res)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -140,8 +163,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'EMT_SynGenDq7odODE_SteadyState'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"EMT_SynGenDq7odODE_SteadyState\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -176,22 +199,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.emt.ph3.SynchronGeneratorDQODE('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.emt.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.emt.ph3.SynchronGeneratorDQODE(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.emt.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.emt.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.emt.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -201,10 +247,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_load', 'i_intf', res)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -237,8 +283,8 @@ "# Define simulation parameters\n", "time_step = 0.0005\n", "final_time = 0.03\n", - "sim_name = 'DP_SynGenDq7odTrapez_SteadyState'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_SynGenDq7odTrapez_SteadyState\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -273,22 +319,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.dp.ph3.SynchronGeneratorDQTrapez('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.dp.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.dp.ph3.SynchronGeneratorDQTrapez(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.dp.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.dp.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.dp.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -298,8 +367,8 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -332,8 +401,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'EMT_SynGenDq7odTrapez_SteadyState'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"EMT_SynGenDq7odTrapez_SteadyState\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -368,22 +437,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.emt.ph3.SynchronGeneratorDQTrapez('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.emt.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.emt.ph3.SynchronGeneratorDQTrapez(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.emt.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.emt.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.emt.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -393,10 +485,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_load', 'i_intf', res)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -425,10 +517,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_SynGenDq7odODE_SteadyState/'\n", - "log_name = 'DP_SynGenDq7odODE_SteadyState'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_ode_ststate = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/DP_SynGenDq7odODE_SteadyState/\"\n", + "log_name = \"DP_SynGenDq7odODE_SteadyState\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_ode_ststate = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_ode_ststate_emt = ts.frequency_shift_list(ts_dpsim_ode_ststate, 60)" ] }, @@ -440,7 +532,13 @@ "source": [ "ts_dpsim_ode_ststate_phasors = ts.phasors(ts_dpsim_ode_ststate)\n", "for node, phasor in ts_dpsim_ode_ststate_phasors.items():\n", - " print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -449,10 +547,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_SynGenDq7odODE_SteadyState/'\n", - "log_name = 'EMT_SynGenDq7odODE_SteadyState'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_emt_ode_ststate = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_SynGenDq7odODE_SteadyState/\"\n", + "log_name = \"EMT_SynGenDq7odODE_SteadyState\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_emt_ode_ststate = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -461,12 +559,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_ode_ststate_emt['v1_0_shift'].time, ts_dpsim_ode_ststate_emt['v1_0_shift'].values)\n", - "plt.plot(ts_dpsim_ode_ststate_emt['v1_1_shift'].time, ts_dpsim_ode_ststate_emt['v1_1_shift'].values)\n", - "plt.plot(ts_dpsim_ode_ststate_emt['v1_2_shift'].time, ts_dpsim_ode_ststate_emt['v1_2_shift'].values)\n", - "plt.plot(ts_dpsim_emt_ode_ststate['v1_0'].time, ts_dpsim_emt_ode_ststate['v1_0'].values)\n", - "plt.plot(ts_dpsim_emt_ode_ststate['v1_1'].time, ts_dpsim_emt_ode_ststate['v1_1'].values)\n", - "plt.plot(ts_dpsim_emt_ode_ststate['v1_2'].time, ts_dpsim_emt_ode_ststate['v1_2'].values)\n", + "plt.plot(\n", + " ts_dpsim_ode_ststate_emt[\"v1_0_shift\"].time,\n", + " ts_dpsim_ode_ststate_emt[\"v1_0_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_ststate_emt[\"v1_1_shift\"].time,\n", + " ts_dpsim_ode_ststate_emt[\"v1_1_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_ststate_emt[\"v1_2_shift\"].time,\n", + " ts_dpsim_ode_ststate_emt[\"v1_2_shift\"].values,\n", + ")\n", + "plt.plot(ts_dpsim_emt_ode_ststate[\"v1_0\"].time, ts_dpsim_emt_ode_ststate[\"v1_0\"].values)\n", + "plt.plot(ts_dpsim_emt_ode_ststate[\"v1_1\"].time, ts_dpsim_emt_ode_ststate[\"v1_1\"].values)\n", + "plt.plot(ts_dpsim_emt_ode_ststate[\"v1_2\"].time, ts_dpsim_emt_ode_ststate[\"v1_2\"].values)\n", "plt.show()" ] }, @@ -483,10 +590,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_SynGenDq7odTrapez_SteadyState/'\n", - "log_name = 'DP_SynGenDq7odTrapez_SteadyState'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_trpz_ststate = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/DP_SynGenDq7odTrapez_SteadyState/\"\n", + "log_name = \"DP_SynGenDq7odTrapez_SteadyState\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_trpz_ststate = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_trpz_ststate_emt = ts.frequency_shift_list(ts_dpsim_trpz_ststate, 60)" ] }, @@ -496,10 +603,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_SynGenDq7odTrapez_SteadyState/'\n", - "log_name = 'EMT_SynGenDq7odTrapez_SteadyState'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_emt_trpz_ststate = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_SynGenDq7odTrapez_SteadyState/\"\n", + "log_name = \"EMT_SynGenDq7odTrapez_SteadyState\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_emt_trpz_ststate = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -508,12 +615,27 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_trpz_ststate_emt['v1_0_shift'].time, ts_dpsim_trpz_ststate_emt['v1_0_shift'].values)\n", - "plt.plot(ts_dpsim_trpz_ststate_emt['v1_1_shift'].time, ts_dpsim_trpz_ststate_emt['v1_1_shift'].values)\n", - "plt.plot(ts_dpsim_trpz_ststate_emt['v1_2_shift'].time, ts_dpsim_trpz_ststate_emt['v1_2_shift'].values)\n", - "plt.plot(ts_dpsim_emt_trpz_ststate['v1_0'].time, ts_dpsim_emt_trpz_ststate['v1_0'].values)\n", - "plt.plot(ts_dpsim_emt_trpz_ststate['v1_1'].time, ts_dpsim_emt_trpz_ststate['v1_1'].values)\n", - "plt.plot(ts_dpsim_emt_trpz_ststate['v1_2'].time, ts_dpsim_emt_trpz_ststate['v1_2'].values)\n", + "plt.plot(\n", + " ts_dpsim_trpz_ststate_emt[\"v1_0_shift\"].time,\n", + " ts_dpsim_trpz_ststate_emt[\"v1_0_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_trpz_ststate_emt[\"v1_1_shift\"].time,\n", + " ts_dpsim_trpz_ststate_emt[\"v1_1_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_trpz_ststate_emt[\"v1_2_shift\"].time,\n", + " ts_dpsim_trpz_ststate_emt[\"v1_2_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_trpz_ststate[\"v1_0\"].time, ts_dpsim_emt_trpz_ststate[\"v1_0\"].values\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_trpz_ststate[\"v1_1\"].time, ts_dpsim_emt_trpz_ststate[\"v1_1\"].values\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_trpz_ststate[\"v1_2\"].time, ts_dpsim_emt_trpz_ststate[\"v1_2\"].values\n", + ")\n", "plt.show()" ] }, @@ -534,12 +656,12 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Simulink/SynchronousGenerator/SynGen_dq_7th_SteadyState/SL_SynGenDq7od_SteadyState_v_i.csv'\n", - "local_file = 'reference-results/SL_SynGenDq7od_SteadyState_v_i.csv'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Simulink/SynchronousGenerator/SynGen_dq_7th_SteadyState/SL_SynGenDq7od_SteadyState_v_i.csv\"\n", + "local_file = \"reference-results/SL_SynGenDq7od_SteadyState_v_i.csv\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", "ts_sl_ststate = rt.read_timeseries_simulink(local_file)" ] @@ -550,10 +672,10 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_sl_ststate['i1'].time, ts_sl_ststate['i1'].values)\n", - "plt.plot(ts_sl_ststate['i2'].time, ts_sl_ststate['i2'].values)\n", - "plt.plot(ts_sl_ststate['i3'].time, ts_sl_ststate['i3'].values)\n", - "plt.xlim(0,0.03)" + "plt.plot(ts_sl_ststate[\"i1\"].time, ts_sl_ststate[\"i1\"].values)\n", + "plt.plot(ts_sl_ststate[\"i2\"].time, ts_sl_ststate[\"i2\"].values)\n", + "plt.plot(ts_sl_ststate[\"i3\"].time, ts_sl_ststate[\"i3\"].values)\n", + "plt.xlim(0, 0.03)" ] }, { @@ -569,13 +691,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_ode_ststate_emt['i_load_0_shift'].time, ts_dpsim_ode_ststate_emt['i_load_0_shift'].values)\n", - "plt.plot(ts_dpsim_ode_ststate_emt['i_load_1_shift'].time, ts_dpsim_ode_ststate_emt['i_load_1_shift'].values)\n", - "plt.plot(ts_dpsim_ode_ststate_emt['i_load_2_shift'].time, ts_dpsim_ode_ststate_emt['i_load_2_shift'].values)\n", - "plt.plot(ts_sl_ststate['i1'].time, ts_sl_ststate['i1'].values)\n", - "plt.plot(ts_sl_ststate['i2'].time, ts_sl_ststate['i2'].values)\n", - "plt.plot(ts_sl_ststate['i3'].time, ts_sl_ststate['i3'].values)\n", - "plt.xlim(0,0.03)" + "plt.plot(\n", + " ts_dpsim_ode_ststate_emt[\"i_load_0_shift\"].time,\n", + " ts_dpsim_ode_ststate_emt[\"i_load_0_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_ststate_emt[\"i_load_1_shift\"].time,\n", + " ts_dpsim_ode_ststate_emt[\"i_load_1_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_ststate_emt[\"i_load_2_shift\"].time,\n", + " ts_dpsim_ode_ststate_emt[\"i_load_2_shift\"].values,\n", + ")\n", + "plt.plot(ts_sl_ststate[\"i1\"].time, ts_sl_ststate[\"i1\"].values)\n", + "plt.plot(ts_sl_ststate[\"i2\"].time, ts_sl_ststate[\"i2\"].values)\n", + "plt.plot(ts_sl_ststate[\"i3\"].time, ts_sl_ststate[\"i3\"].values)\n", + "plt.xlim(0, 0.03)" ] }, { diff --git a/examples/Notebooks/Components/SynGenDq7od_ThreePhFault_DP_EMT.ipynb b/examples/Notebooks/Components/SynGenDq7od_ThreePhFault_DP_EMT.ipynb index 780edc6f62..58286c9bbf 100644 --- a/examples/Notebooks/Components/SynGenDq7od_ThreePhFault_DP_EMT.ipynb +++ b/examples/Notebooks/Components/SynGenDq7od_ThreePhFault_DP_EMT.ipynb @@ -46,8 +46,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'DP_SynGenDq7odODE_ThreePhFault'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_SynGenDq7odODE_ThreePhFault\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -82,22 +82,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.dp.ph3.SynchronGeneratorDQODE('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.dp.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.dp.ph3.SynchronGeneratorDQODE(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.dp.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.dp.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.dp.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -107,10 +130,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_load', 'i_intf', res)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -150,8 +173,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'EMT_SynGenDq7odODE_ThreePhFault'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"EMT_SynGenDq7odODE_ThreePhFault\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -186,22 +209,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.emt.ph3.SynchronGeneratorDQODE('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.emt.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.emt.ph3.SynchronGeneratorDQODE(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.emt.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.emt.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.emt.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -211,10 +257,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_load', 'i_intf', res)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -254,8 +300,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'DP_SynGenDq7odTrapez_ThreePhFault'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_SynGenDq7odTrapez_ThreePhFault\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -290,22 +336,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.dp.ph3.SynchronGeneratorDQTrapez('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.dp.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.dp.ph3.SynchronGeneratorDQTrapez(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.dp.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.dp.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.dp.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -315,8 +384,8 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -356,8 +425,8 @@ "# Define simulation parameters\n", "time_step = 0.00005\n", "final_time = 0.3\n", - "sim_name = 'EMT_SynGenDq7odTrapez_ThreePhFault'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"EMT_SynGenDq7odTrapez_ThreePhFault\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -392,22 +461,45 @@ "breaker_closed = 0.001\n", "\n", "# Nodes\n", - "init_volt_n1 = [init_terminal_volt * np.exp(init_volt_angle * 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3)* 1j),\n", - " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3)* 1j)]\n", - "n1 = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC, init_volt_n1)\n", + "init_volt_n1 = [\n", + " init_terminal_volt * np.exp(init_volt_angle * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle - 2 * np.pi / 3) * 1j),\n", + " init_terminal_volt * np.exp((init_volt_angle + 2 * np.pi / 3) * 1j),\n", + "]\n", + "n1 = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC, init_volt_n1)\n", "\n", "# Components\n", - "gen = dpsimpy.emt.ph3.SynchronGeneratorDQTrapez('SynGen')\n", - "gen.set_parameters_fundamental_per_unit(nom_power, nom_ph_ph_volt_rms, nom_freq, pole_num, nom_field_curr, Rs,\n", - " Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,\n", - " Llkq2, H, init_active_power, init_reactive_power, init_terminal_volt, init_volt_angle,\n", - " init_mech_power)\n", - "\n", - "res = dpsimpy.emt.ph3.SeriesResistor('R_load')\n", + "gen = dpsimpy.emt.ph3.SynchronGeneratorDQTrapez(\"SynGen\")\n", + "gen.set_parameters_fundamental_per_unit(\n", + " nom_power,\n", + " nom_ph_ph_volt_rms,\n", + " nom_freq,\n", + " pole_num,\n", + " nom_field_curr,\n", + " Rs,\n", + " Ll,\n", + " Lmd,\n", + " Lmq,\n", + " Rfd,\n", + " Llfd,\n", + " Rkd,\n", + " Llkd,\n", + " Rkq1,\n", + " Llkq1,\n", + " Rkq2,\n", + " Llkq2,\n", + " H,\n", + " init_active_power,\n", + " init_reactive_power,\n", + " init_terminal_volt,\n", + " init_volt_angle,\n", + " init_mech_power,\n", + ")\n", + "\n", + "res = dpsimpy.emt.ph3.SeriesResistor(\"R_load\")\n", "res.set_parameters(R_load)\n", "\n", - "fault = dpsimpy.emt.ph3.SeriesSwitch('Br_fault')\n", + "fault = dpsimpy.emt.ph3.SeriesSwitch(\"Br_fault\")\n", "fault.set_parameters(breaker_open, breaker_closed)\n", "\n", "# Connections\n", @@ -417,10 +509,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_load', 'i_intf', res)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# System\n", "sys = dpsimpy.SystemTopology(60, [n1], [gen, res, fault])\n", @@ -456,10 +548,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_SynGenDq7odODE_ThreePhFault/'\n", - "log_name = 'DP_SynGenDq7odODE_ThreePhFault'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_ode_tpf = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/DP_SynGenDq7odODE_ThreePhFault/\"\n", + "log_name = \"DP_SynGenDq7odODE_ThreePhFault\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_ode_tpf = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_ode_tpf_emt = ts.frequency_shift_list(ts_dpsim_ode_tpf, 60)" ] }, @@ -471,7 +563,13 @@ "source": [ "ts_dpsim_ode_tpf_phasors = ts.phasors(ts_dpsim_ode_tpf)\n", "for node, phasor in ts_dpsim_ode_tpf_phasors.items():\n", - " print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -480,10 +578,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_SynGenDq7odODE_ThreePhFault/'\n", - "log_name = 'EMT_SynGenDq7odODE_ThreePhFault'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_emt_ode_tpf = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_SynGenDq7odODE_ThreePhFault/\"\n", + "log_name = \"EMT_SynGenDq7odODE_ThreePhFault\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_emt_ode_tpf = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -492,9 +590,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_ode_tpf_emt['v1_0_shift'].time, ts_dpsim_ode_tpf_emt['v1_0_shift'].values)\n", - "plt.plot(ts_dpsim_ode_tpf_emt['v1_1_shift'].time, ts_dpsim_ode_tpf_emt['v1_1_shift'].values)\n", - "plt.plot(ts_dpsim_ode_tpf_emt['v1_2_shift'].time, ts_dpsim_ode_tpf_emt['v1_2_shift'].values)\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"v1_0_shift\"].time, ts_dpsim_ode_tpf_emt[\"v1_0_shift\"].values\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"v1_1_shift\"].time, ts_dpsim_ode_tpf_emt[\"v1_1_shift\"].values\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"v1_2_shift\"].time, ts_dpsim_ode_tpf_emt[\"v1_2_shift\"].values\n", + ")\n", "plt.show()" ] }, @@ -504,12 +608,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_0_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_0_shift'].values)\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_1_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_1_shift'].values)\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_2_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_2_shift'].values)\n", - "plt.plot(ts_dpsim_emt_ode_tpf['i_gen_0'].time, ts_dpsim_emt_ode_tpf['i_gen_0'].values)\n", - "plt.plot(ts_dpsim_emt_ode_tpf['i_gen_1'].time, ts_dpsim_emt_ode_tpf['i_gen_1'].values)\n", - "plt.plot(ts_dpsim_emt_ode_tpf['i_gen_2'].time, ts_dpsim_emt_ode_tpf['i_gen_2'].values)\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].values,\n", + ")\n", + "plt.plot(ts_dpsim_emt_ode_tpf[\"i_gen_0\"].time, ts_dpsim_emt_ode_tpf[\"i_gen_0\"].values)\n", + "plt.plot(ts_dpsim_emt_ode_tpf[\"i_gen_1\"].time, ts_dpsim_emt_ode_tpf[\"i_gen_1\"].values)\n", + "plt.plot(ts_dpsim_emt_ode_tpf[\"i_gen_2\"].time, ts_dpsim_emt_ode_tpf[\"i_gen_2\"].values)\n", "plt.show()" ] }, @@ -527,10 +640,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_SynGenDq7odTrapez_ThreePhFault/'\n", - "log_name = 'DP_SynGenDq7odTrapez_ThreePhFault'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_trapez_tpf = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/DP_SynGenDq7odTrapez_ThreePhFault/\"\n", + "log_name = \"DP_SynGenDq7odTrapez_ThreePhFault\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_trapez_tpf = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_trapez_tpf_emt = ts.frequency_shift_list(ts_dpsim_trapez_tpf, 60)" ] }, @@ -540,10 +653,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_SynGenDq7odTrapez_ThreePhFault/'\n", - "log_name = 'EMT_SynGenDq7odTrapez_ThreePhFault'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_emt_trapez_tpf = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_SynGenDq7odTrapez_ThreePhFault/\"\n", + "log_name = \"EMT_SynGenDq7odTrapez_ThreePhFault\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_emt_trapez_tpf = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -552,12 +665,27 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_trapez_tpf_emt['i_gen_0_shift'].time, ts_dpsim_trapez_tpf_emt['i_gen_0_shift'].values)\n", - "plt.plot(ts_dpsim_trapez_tpf_emt['i_gen_1_shift'].time, ts_dpsim_trapez_tpf_emt['i_gen_1_shift'].values)\n", - "plt.plot(ts_dpsim_trapez_tpf_emt['i_gen_2_shift'].time, ts_dpsim_trapez_tpf_emt['i_gen_2_shift'].values)\n", - "plt.plot(ts_dpsim_emt_trapez_tpf['i_gen_0'].time, ts_dpsim_emt_trapez_tpf['i_gen_0'].values)\n", - "plt.plot(ts_dpsim_emt_trapez_tpf['i_gen_1'].time, ts_dpsim_emt_trapez_tpf['i_gen_1'].values)\n", - "plt.plot(ts_dpsim_emt_trapez_tpf['i_gen_2'].time, ts_dpsim_emt_trapez_tpf['i_gen_2'].values)\n", + "plt.plot(\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_0_shift\"].time,\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_0_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_1_shift\"].time,\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_1_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_2_shift\"].time,\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_2_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_trapez_tpf[\"i_gen_0\"].time, ts_dpsim_emt_trapez_tpf[\"i_gen_0\"].values\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_trapez_tpf[\"i_gen_1\"].time, ts_dpsim_emt_trapez_tpf[\"i_gen_1\"].values\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_trapez_tpf[\"i_gen_2\"].time, ts_dpsim_emt_trapez_tpf[\"i_gen_2\"].values\n", + ")\n", "plt.show()" ] }, @@ -579,15 +707,16 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Simulink/SynchronousGenerator/SynGen_dq_7th_ThreePhFault/SL_SynGenDq7od_ThreePhFault_v_i.csv'\n", - "local_file = 'reference-results/SL_SynGenDq7od_ThreePhFault_v_i.csv'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Simulink/SynchronousGenerator/SynGen_dq_7th_ThreePhFault/SL_SynGenDq7od_ThreePhFault_v_i.csv\"\n", + "local_file = \"reference-results/SL_SynGenDq7od_ThreePhFault_v_i.csv\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", "import villas.dataprocessing.readtools as rt\n", - "import matplotlib.pyplot as plt \n", + "import matplotlib.pyplot as plt\n", + "\n", "ts_sl_tpf = rt.read_timeseries_simulink(local_file)" ] }, @@ -597,16 +726,16 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_sl_tpf['v1'].time, ts_sl_tpf['v1'].values)\n", - "plt.plot(ts_sl_tpf['v2'].time, ts_sl_tpf['v2'].values)\n", - "plt.plot(ts_sl_tpf['v3'].time, ts_sl_tpf['v3'].values)\n", - "plt.xlim(0,0.3)\n", + "plt.plot(ts_sl_tpf[\"v1\"].time, ts_sl_tpf[\"v1\"].values)\n", + "plt.plot(ts_sl_tpf[\"v2\"].time, ts_sl_tpf[\"v2\"].values)\n", + "plt.plot(ts_sl_tpf[\"v3\"].time, ts_sl_tpf[\"v3\"].values)\n", + "plt.xlim(0, 0.3)\n", "\n", "plt.figure()\n", - "plt.plot(ts_sl_tpf['i1'].time, ts_sl_tpf['i1'].values)\n", - "plt.plot(ts_sl_tpf['i2'].time, ts_sl_tpf['i2'].values)\n", - "plt.plot(ts_sl_tpf['i3'].time, ts_sl_tpf['i3'].values)\n", - "plt.xlim(0,0.3)" + "plt.plot(ts_sl_tpf[\"i1\"].time, ts_sl_tpf[\"i1\"].values)\n", + "plt.plot(ts_sl_tpf[\"i2\"].time, ts_sl_tpf[\"i2\"].values)\n", + "plt.plot(ts_sl_tpf[\"i3\"].time, ts_sl_tpf[\"i3\"].values)\n", + "plt.xlim(0, 0.3)" ] }, { @@ -623,24 +752,43 @@ "metadata": {}, "outputs": [], "source": [ - "#%matplotlib qt\n", + "# %matplotlib qt\n", "import matplotlib.pyplot as plt\n", - "ts_sl_tpf_i1 = ts('i1', ts_sl_tpf['i1'].time, -ts_sl_tpf['i1'].values)\n", - "ts_sl_tpf_i2 = ts('i2', ts_sl_tpf['i2'].time, -ts_sl_tpf['i2'].values)\n", - "ts_sl_tpf_i3 = ts('i3', ts_sl_tpf['i3'].time, -ts_sl_tpf['i3'].values)\n", - "\n", - "#plt.figure(figsize=(20,10))\n", - "plt.plot(ts_sl_tpf_i1.time, ts_sl_tpf_i1.values, color = '#939393ff', label = 'ia_sl')\n", - "plt.plot(ts_sl_tpf_i2.time, ts_sl_tpf_i2.values, color = '#939393ff', label = 'ib_sl')\n", - "plt.plot(ts_sl_tpf_i3.time, ts_sl_tpf_i3.values, color = '#939393ff', label = 'ic_sl')\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_0_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_0_shift'].values, linestyle='-.', color = '#d62728ff', label = 'ia_dpsim')\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_1_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_1_shift'].values, linestyle='-.', color = '#0055ffff', label = 'ib_dpsim')\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_2_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_2_shift'].values, linestyle='-.', color = '#00aa7fff', label = 'ic_dpsim')\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (V)')\n", - "plt.xlim(0.05,0.25)\n", - "#plt.ylim(-1.6e5,1.6e5)\n", - "#plt.savefig('syngen_fault_ode.pdf')" + "\n", + "ts_sl_tpf_i1 = ts(\"i1\", ts_sl_tpf[\"i1\"].time, -ts_sl_tpf[\"i1\"].values)\n", + "ts_sl_tpf_i2 = ts(\"i2\", ts_sl_tpf[\"i2\"].time, -ts_sl_tpf[\"i2\"].values)\n", + "ts_sl_tpf_i3 = ts(\"i3\", ts_sl_tpf[\"i3\"].time, -ts_sl_tpf[\"i3\"].values)\n", + "\n", + "# plt.figure(figsize=(20,10))\n", + "plt.plot(ts_sl_tpf_i1.time, ts_sl_tpf_i1.values, color=\"#939393ff\", label=\"ia_sl\")\n", + "plt.plot(ts_sl_tpf_i2.time, ts_sl_tpf_i2.values, color=\"#939393ff\", label=\"ib_sl\")\n", + "plt.plot(ts_sl_tpf_i3.time, ts_sl_tpf_i3.values, color=\"#939393ff\", label=\"ic_sl\")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].values,\n", + " linestyle=\"-.\",\n", + " color=\"#d62728ff\",\n", + " label=\"ia_dpsim\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].values,\n", + " linestyle=\"-.\",\n", + " color=\"#0055ffff\",\n", + " label=\"ib_dpsim\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].values,\n", + " linestyle=\"-.\",\n", + " color=\"#00aa7fff\",\n", + " label=\"ic_dpsim\",\n", + ")\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (V)\")\n", + "plt.xlim(0.05, 0.25)\n", + "# plt.ylim(-1.6e5,1.6e5)\n", + "# plt.savefig('syngen_fault_ode.pdf')" ] }, { @@ -649,12 +797,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_ode_tpf_phasors['i_gen_0']['phase'].time, ts_dpsim_ode_tpf_phasors['i_gen_0']['phase'].values)\n", - "plt.xlim([0.09,0.21])\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_phasors[\"i_gen_0\"][\"phase\"].time,\n", + " ts_dpsim_ode_tpf_phasors[\"i_gen_0\"][\"phase\"].values,\n", + ")\n", + "plt.xlim([0.09, 0.21])\n", "\n", "plt.figure()\n", - "plt.plot(ts_dpsim_ode_tpf['wr_gen'].time, ts_dpsim_ode_tpf['wr_gen'].values * 60)\n", - "plt.xlim([0.09,0.21])" + "plt.plot(ts_dpsim_ode_tpf[\"wr_gen\"].time, ts_dpsim_ode_tpf[\"wr_gen\"].values * 60)\n", + "plt.xlim([0.09, 0.21])" ] }, { @@ -664,7 +815,8 @@ "outputs": [], "source": [ "import numpy as np\n", - "diff = ts_sl_tpf_i1.values - ts_dpsim_ode_tpf_emt['i_gen_0_shift'].values\n", + "\n", + "diff = ts_sl_tpf_i1.values - ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].values\n", "print(np.max(diff[:4000]))\n", "assert np.max(diff[:4000]) < 28.5" ] @@ -683,17 +835,26 @@ "metadata": {}, "outputs": [], "source": [ - "ts_sl_tpf_i1 = ts('i1', ts_sl_tpf['i1'].time, -ts_sl_tpf['i1'].values)\n", - "ts_sl_tpf_i2 = ts('i2', ts_sl_tpf['i2'].time, -ts_sl_tpf['i2'].values)\n", - "ts_sl_tpf_i3 = ts('i3', ts_sl_tpf['i3'].time, -ts_sl_tpf['i3'].values)\n", + "ts_sl_tpf_i1 = ts(\"i1\", ts_sl_tpf[\"i1\"].time, -ts_sl_tpf[\"i1\"].values)\n", + "ts_sl_tpf_i2 = ts(\"i2\", ts_sl_tpf[\"i2\"].time, -ts_sl_tpf[\"i2\"].values)\n", + "ts_sl_tpf_i3 = ts(\"i3\", ts_sl_tpf[\"i3\"].time, -ts_sl_tpf[\"i3\"].values)\n", "\n", - "#plt.figure(figsize=(20,10))\n", + "# plt.figure(figsize=(20,10))\n", "plt.plot(ts_sl_tpf_i1.time, ts_sl_tpf_i1.values)\n", "plt.plot(ts_sl_tpf_i2.time, ts_sl_tpf_i2.values)\n", "plt.plot(ts_sl_tpf_i3.time, ts_sl_tpf_i3.values)\n", - "plt.plot(ts_dpsim_trapez_tpf_emt['i_gen_0_shift'].time, ts_dpsim_trapez_tpf_emt['i_gen_0_shift'].values)\n", - "plt.plot(ts_dpsim_trapez_tpf_emt['i_gen_1_shift'].time, ts_dpsim_trapez_tpf_emt['i_gen_1_shift'].values)\n", - "plt.plot(ts_dpsim_trapez_tpf_emt['i_gen_2_shift'].time, ts_dpsim_trapez_tpf_emt['i_gen_2_shift'].values)\n", + "plt.plot(\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_0_shift\"].time,\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_0_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_1_shift\"].time,\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_1_shift\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_2_shift\"].time,\n", + " ts_dpsim_trapez_tpf_emt[\"i_gen_2_shift\"].values,\n", + ")\n", "plt.show()" ] }, @@ -704,7 +865,8 @@ "outputs": [], "source": [ "import numpy as np\n", - "diff = ts_sl_tpf_i1.values - ts_dpsim_trapez_tpf_emt['i_gen_0_shift'].values\n", + "\n", + "diff = ts_sl_tpf_i1.values - ts_dpsim_trapez_tpf_emt[\"i_gen_0_shift\"].values\n", "print(np.max(diff[:4000]))\n", "assert np.max(diff[:4000]) < 30.6" ] diff --git a/examples/Notebooks/Components/SynGen_trStab.ipynb b/examples/Notebooks/Components/SynGen_trStab.ipynb index 4ec8b63b7e..5c78602171 100644 --- a/examples/Notebooks/Components/SynGen_trStab.ipynb +++ b/examples/Notebooks/Components/SynGen_trStab.ipynb @@ -39,8 +39,8 @@ " # Define simulation parameters\n", " time_step = 0.0005\n", " final_time = 0.03\n", - " sim_name = 'DP_SynGen_TrStab_SteadyState'\n", - " dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + " sim_name = \"DP_SynGen_TrStab_SteadyState\"\n", + " dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", " # Define machine parameters in per unit\n", " nom_power = 555e6\n", @@ -62,15 +62,17 @@ " R_load = 1.92\n", "\n", " # Nodes\n", - " n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [init_voltage])\n", + " n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single, [init_voltage])\n", "\n", " # Components\n", - " gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab('SynGen', dpsimpy.LogLevel.debug)\n", - " gen.set_fundamental_parameters_PU(nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H)\n", + " gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab(\"SynGen\", dpsimpy.LogLevel.debug)\n", + " gen.set_fundamental_parameters_PU(\n", + " nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H\n", + " )\n", " gen.connect([n1])\n", " gen.set_initial_values(init_elec_power, mech_power)\n", "\n", - " res = dpsimpy.dp.ph1.Resistor('Rl', dpsimpy.LogLevel.debug)\n", + " res = dpsimpy.dp.ph1.Resistor(\"Rl\", dpsimpy.LogLevel.debug)\n", " res.set_parameters(R_load)\n", " res.connect([dpsimpy.dp.SimNode.gnd, n1])\n", "\n", @@ -79,10 +81,10 @@ "\n", " # Logging\n", " logger = dpsimpy.Logger(sim_name)\n", - " logger.log_attribute('v1', 'v', n1)\n", - " logger.log_attribute('i_gen', 'i_intf', gen)\n", - " logger.log_attribute('i_load', 'i_intf', res)\n", - " logger.log_attribute('wr_gen', 'w_r', gen)\n", + " logger.log_attribute(\"v1\", \"v\", n1)\n", + " logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + " logger.log_attribute(\"i_load\", \"i_intf\", res)\n", + " logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", " # Simulation\n", " sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.trace)\n", @@ -92,7 +94,7 @@ " sim.set_final_time(final_time)\n", " sim.set_domain(dpsimpy.Domain.DP)\n", " sim.add_logger(logger)\n", - " sim.run()\n" + " sim.run()" ] }, { @@ -111,10 +113,10 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = 'logs/DP_SynGen_TrStab_SteadyState/'\n", - "logName_ststate = 'DP_SynGen_TrStab_SteadyState_LeftVector'\n", - "print(work_dir + logName_ststate + '.csv')\n", - "ts_dpsim_ststate = rt.read_timeseries_dpsim(work_dir + logName_ststate + '.csv')\n", + "work_dir = \"logs/DP_SynGen_TrStab_SteadyState/\"\n", + "logName_ststate = \"DP_SynGen_TrStab_SteadyState_LeftVector\"\n", + "print(work_dir + logName_ststate + \".csv\")\n", + "ts_dpsim_ststate = rt.read_timeseries_dpsim(work_dir + logName_ststate + \".csv\")\n", "ts_dpsim_ststate_emt = ts.frequency_shift_list(ts_dpsim_ststate, 60)\n", "phasors_ststate = ts.phasors(ts_dpsim_ststate)" ] @@ -126,7 +128,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_ststate.items():\n", - " print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -135,8 +143,8 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, ts_dpsim_ststate_emt['n00000f00_shift'])\n", - "pt.plot_timeseries(1, ts_dpsim_ststate_emt['n00001f00_shift'])" + "pt.plot_timeseries(1, ts_dpsim_ststate_emt[\"n00000f00_shift\"])\n", + "pt.plot_timeseries(1, ts_dpsim_ststate_emt[\"n00001f00_shift\"])" ] }, { @@ -146,10 +154,10 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = './logs/DP_SynGen_TrStab_SteadyState/'\n", - "logName_ststate = 'DP_SynGen_TrStab_SteadyState'\n", - "print(work_dir + logName_ststate + '.csv')\n", - "ts_dpsim_ststate = rt.read_timeseries_dpsim(work_dir + logName_ststate + '.csv')\n", + "work_dir = \"./logs/DP_SynGen_TrStab_SteadyState/\"\n", + "logName_ststate = \"DP_SynGen_TrStab_SteadyState\"\n", + "print(work_dir + logName_ststate + \".csv\")\n", + "ts_dpsim_ststate = rt.read_timeseries_dpsim(work_dir + logName_ststate + \".csv\")\n", "ts_dpsim_ststate_emt = ts.frequency_shift_list(ts_dpsim_ststate, 60)\n", "phasors_ststate = ts.phasors(ts_dpsim_ststate)" ] @@ -160,7 +168,13 @@ "metadata": {}, "outputs": [], "source": [ - "print('v1' + ': ' + str(phasors_ststate['v1']['abs'].values[0]) + '<' + str(phasors_ststate['v1']['phase'].values[0]))" + "print(\n", + " \"v1\"\n", + " + \": \"\n", + " + str(phasors_ststate[\"v1\"][\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasors_ststate[\"v1\"][\"phase\"].values[0])\n", + ")" ] }, { @@ -169,8 +183,8 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, ts_dpsim_ststate['wr_gen'])\n", - "plt.ylim([375,380])" + "pt.plot_timeseries(1, ts_dpsim_ststate[\"wr_gen\"])\n", + "plt.ylim([375, 380])" ] }, { @@ -180,7 +194,11 @@ "outputs": [], "source": [ "import numpy as np\n", - "assert np.max(ts_dpsim_ststate['wr_gen'].values[0] - ts_dpsim_ststate['wr_gen'].values[-1]) < 0.001" + "\n", + "assert (\n", + " np.max(ts_dpsim_ststate[\"wr_gen\"].values[0] - ts_dpsim_ststate[\"wr_gen\"].values[-1])\n", + " < 0.001\n", + ")" ] }, { @@ -199,8 +217,8 @@ "# Define simulation parameters\n", "time_step = 0.0005\n", "final_time = 0.1\n", - "sim_name = 'DP_SynGen_TrStab_LoadStep'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_SynGen_TrStab_LoadStep\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -223,15 +241,17 @@ "R_load_step = 0.7\n", "\n", "# Nodes\n", - "n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [init_voltage])\n", + "n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single, [init_voltage])\n", "\n", "# Components\n", - "gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab('SynGen', dpsimpy.LogLevel.debug)\n", - "gen.set_fundamental_parameters_PU(nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H)\n", + "gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab(\"SynGen\", dpsimpy.LogLevel.debug)\n", + "gen.set_fundamental_parameters_PU(\n", + " nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H\n", + ")\n", "gen.connect([n1])\n", "gen.set_initial_values(init_elec_power, mech_power)\n", "\n", - "load = dpsimpy.dp.ph1.Switch('StepLoad', dpsimpy.LogLevel.debug)\n", + "load = dpsimpy.dp.ph1.Switch(\"StepLoad\", dpsimpy.LogLevel.debug)\n", "load.set_parameters(R_load, R_load_step)\n", "load.connect([dpsimpy.dp.SimNode.gnd, n1])\n", "load.open()\n", @@ -241,10 +261,10 @@ "\n", "# Logging\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('i_gen', 'i_intf', gen)\n", - "logger.log_attribute('i_load', 'i_intf', load)\n", - "logger.log_attribute('wr_gen', 'w_r', gen)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"i_gen\", \"i_intf\", gen)\n", + "logger.log_attribute(\"i_load\", \"i_intf\", load)\n", + "logger.log_attribute(\"wr_gen\", \"w_r\", gen)\n", "\n", "# Simulation\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.info)\n", @@ -259,7 +279,7 @@ "sw1 = dpsimpy.event.SwitchEvent(0.05, load, True)\n", "sim.add_event(sw1)\n", "\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -269,10 +289,10 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = 'logs/DP_SynGen_TrStab_LoadStep/'\n", - "logName = 'DP_SynGen_TrStab_LoadStep'\n", - "print(work_dir + logName + '.csv')\n", - "ts_dpsim_loadstep= rt.read_timeseries_dpsim(work_dir + logName + '.csv')\n", + "work_dir = \"logs/DP_SynGen_TrStab_LoadStep/\"\n", + "logName = \"DP_SynGen_TrStab_LoadStep\"\n", + "print(work_dir + logName + \".csv\")\n", + "ts_dpsim_loadstep = rt.read_timeseries_dpsim(work_dir + logName + \".csv\")\n", "ts_dpsim_loadstep_emt = ts.frequency_shift_list(ts_dpsim_loadstep, 60)\n", "phasors_loadstep = ts.phasors(ts_dpsim_loadstep)" ] @@ -283,7 +303,13 @@ "metadata": {}, "outputs": [], "source": [ - "print('v1' + ': ' + str(phasors_loadstep['v1']['abs'].values[0]) + '<' + str(phasors_loadstep['v1']['phase'].values[0]))" + "print(\n", + " \"v1\"\n", + " + \": \"\n", + " + str(phasors_loadstep[\"v1\"][\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasors_loadstep[\"v1\"][\"phase\"].values[0])\n", + ")" ] }, { @@ -292,8 +318,8 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(2, ts_dpsim_loadstep_emt['v1_shift'])\n", - "plt.xlim(0.03, 0.07) " + "pt.plot_timeseries(2, ts_dpsim_loadstep_emt[\"v1_shift\"])\n", + "plt.xlim(0.03, 0.07)" ] }, { @@ -302,7 +328,7 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(3, ts_dpsim_loadstep['wr_gen'])" + "pt.plot_timeseries(3, ts_dpsim_loadstep[\"wr_gen\"])" ] }, { @@ -311,7 +337,12 @@ "metadata": {}, "outputs": [], "source": [ - "assert np.max(ts_dpsim_loadstep['wr_gen'].values[0] - ts_dpsim_loadstep['wr_gen'].values[-1]) < 5" + "assert (\n", + " np.max(\n", + " ts_dpsim_loadstep[\"wr_gen\"].values[0] - ts_dpsim_loadstep[\"wr_gen\"].values[-1]\n", + " )\n", + " < 5\n", + ")" ] } ], diff --git a/examples/Notebooks/Components/SynGen_trStab_logger_test.ipynb b/examples/Notebooks/Components/SynGen_trStab_logger_test.ipynb index 1a1d341bb5..85b4b8fbc4 100644 --- a/examples/Notebooks/Components/SynGen_trStab_logger_test.ipynb +++ b/examples/Notebooks/Components/SynGen_trStab_logger_test.ipynb @@ -32,8 +32,8 @@ " # Define simulation parameters\n", " time_step = 0.0005\n", " final_time = 0.03\n", - " sim_name = 'DP_SynGen_TrStab_SteadyState'\n", - " dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + " sim_name = \"DP_SynGen_TrStab_SteadyState\"\n", + " dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", " # Define machine parameters in per unit\n", " nom_power = 555e6\n", @@ -55,21 +55,23 @@ " R_load = 1.92\n", "\n", " # Nodes\n", - " n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [init_voltage])\n", + " n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single, [init_voltage])\n", "\n", " # Components\n", - " gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab('SynGen', dpsimpy.LogLevel.debug)\n", - " gen.set_fundamental_parameters_PU(nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H)\n", + " gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab(\"SynGen\", dpsimpy.LogLevel.debug)\n", + " gen.set_fundamental_parameters_PU(\n", + " nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H\n", + " )\n", " gen.connect([n1])\n", " gen.set_initial_values(init_elec_power, mech_power)\n", "\n", - " res = dpsimpy.dp.ph1.Resistor('Rl', dpsimpy.LogLevel.debug)\n", + " res = dpsimpy.dp.ph1.Resistor(\"Rl\", dpsimpy.LogLevel.debug)\n", " res.set_parameters(R_load)\n", " res.connect([dpsimpy.dp.SimNode.gnd, n1])\n", "\n", " # System\n", " sys = dpsimpy.SystemTopology(60, [n1], [gen, res])\n", - " \n", + "\n", " # Simulation\n", " sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.trace)\n", " sim.set_time_step(time_step)\n", @@ -87,11 +89,14 @@ "outputs": [], "source": [ "def printTrStabLeftVector():\n", - " f = open('logs/DP_SynGen_TrStab_SteadyState/DP_SynGen_TrStab_SteadyState_LeftVector.csv', 'r')\n", + " f = open(\n", + " \"logs/DP_SynGen_TrStab_SteadyState/DP_SynGen_TrStab_SteadyState_LeftVector.csv\",\n", + " \"r\",\n", + " )\n", " content = f.read()\n", - " print('----- Start of LeftVector-File -----')\n", + " print(\"----- Start of LeftVector-File -----\")\n", " print(content)\n", - " print('----- End of LeftVector-File -----\\n')\n", + " print(\"----- End of LeftVector-File -----\\n\")\n", " f.close()" ] }, @@ -101,11 +106,11 @@ "metadata": {}, "outputs": [], "source": [ - " # Define simulation parameters\n", + "# Define simulation parameters\n", "time_step = 0.0005\n", "final_time = 0.03\n", - "sim_name = 'DP_SynGen_TrStab_SteadyState'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_SynGen_TrStab_SteadyState\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "# Define machine parameters in per unit\n", "nom_power = 555e6\n", @@ -127,15 +132,17 @@ "R_load = 1.92\n", "\n", "# Nodes\n", - "n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [init_voltage])\n", + "n1 = dpsimpy.dp.SimNode(\"n1\", dpsimpy.PhaseType.Single, [init_voltage])\n", "\n", "# Components\n", - "gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab('SynGen', dpsimpy.LogLevel.debug)\n", - "gen.set_fundamental_parameters_PU(nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H)\n", + "gen = dpsimpy.dp.ph1.SynchronGeneratorTrStab(\"SynGen\", dpsimpy.LogLevel.debug)\n", + "gen.set_fundamental_parameters_PU(\n", + " nom_power, nom_ph_ph_volt_rms, nom_freq, Ll, Lmd, Llfd, H\n", + ")\n", "gen.connect([n1])\n", "gen.set_initial_values(init_elec_power, mech_power)\n", "\n", - "res = dpsimpy.dp.ph1.Resistor('Rl', dpsimpy.LogLevel.debug)\n", + "res = dpsimpy.dp.ph1.Resistor(\"Rl\", dpsimpy.LogLevel.debug)\n", "res.set_parameters(R_load)\n", "res.connect([dpsimpy.dp.SimNode.gnd, n1])\n", "\n", @@ -151,11 +158,11 @@ "sim1.set_system(sys)\n", "sim1.run()\n", "\n", - "print('LeftVector-File after running simulation in the same cell')\n", + "print(\"LeftVector-File after running simulation in the same cell\")\n", "printTrStabLeftVector()\n", "\n", "SimTrStab()\n", - "print('LeftVector-File after running simulation in a function')\n", + "print(\"LeftVector-File after running simulation in a function\")\n", "printTrStabLeftVector()" ] } diff --git a/examples/Notebooks/Components/Syngen_9Order_DCIM_VBR_Governor_Exciter.ipynb b/examples/Notebooks/Components/Syngen_9Order_DCIM_VBR_Governor_Exciter.ipynb index c0205c180a..e2068ff37a 100644 --- a/examples/Notebooks/Components/Syngen_9Order_DCIM_VBR_Governor_Exciter.ipynb +++ b/examples/Notebooks/Components/Syngen_9Order_DCIM_VBR_Governor_Exciter.ipynb @@ -22,13 +22,18 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "\n", - "PEAK1PH_TO_RMS3PH=np.sqrt(3./2.)\n", + "PEAK1PH_TO_RMS3PH = np.sqrt(3.0 / 2.0)\n", "\n", - "root_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", + "root_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", "\n", - "path_exec = root_path + '/build/dpsim/examples/cxx/'\n", + "path_exec = root_path + \"/build/dpsim/examples/cxx/\"\n", "\n", "finalTime = 30.0\n", "\n", @@ -52,15 +57,31 @@ "metadata": {}, "outputs": [], "source": [ - "name_exec = 'EMT_SynchronGenerator9OrderDCIM_LoadStep_TurbineGovernor_Exciter'\n", + "name_exec = \"EMT_SynchronGenerator9OrderDCIM_LoadStep_TurbineGovernor_Exciter\"\n", "\n", "model_name = name_exec\n", "\n", - "sim = subprocess.Popen([path_exec+name_exec, '--name', model_name, '--timestep', str(timeStepDCIM), '--duration', str(finalTime), '--option', 'TIMESTEPEVENT='+str(loadStepEventTime), '--option', 'LOADFACTOR='+str(loadFactor)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timeStepDCIM),\n", + " \"--duration\",\n", + " str(finalTime),\n", + " \"--option\",\n", + " \"TIMESTEPEVENT=\" + str(loadStepEventTime),\n", + " \"--option\",\n", + " \"LOADFACTOR=\" + str(loadFactor),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt_dcim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -77,15 +98,31 @@ "metadata": {}, "outputs": [], "source": [ - "name_exec = 'EMT_SynchronGenerator9OrderVBR_LoadStep_TurbineGovernor_Exciter'\n", + "name_exec = \"EMT_SynchronGenerator9OrderVBR_LoadStep_TurbineGovernor_Exciter\"\n", "\n", "model_name = name_exec\n", "\n", - "sim = subprocess.Popen([path_exec+name_exec, '--name', model_name, '--timestep', str(timeStepVBR), '--duration', str(finalTime), '--option', 'TIMESTEPEVENT='+str(loadStepEventTime), '--option', 'LOADFACTOR='+str(loadFactor)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timeStepVBR),\n", + " \"--duration\",\n", + " str(finalTime),\n", + " \"--option\",\n", + " \"TIMESTEPEVENT=\" + str(loadStepEventTime),\n", + " \"--option\",\n", + " \"LOADFACTOR=\" + str(loadFactor),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt_vbr = read_timeseries_csv(dpsim_result_file)" ] }, @@ -102,10 +139,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'v1_0'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt_dcim[name].values, label='dcim')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt_vbr[name].values, label='vbr', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"v1_0\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -123,10 +169,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'i_gen_0'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label='dcim')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, ts_dpsim_emt_vbr[name].values, label='vbr', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"i_gen_0\"\n", + "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label=\"dcim\")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -144,10 +195,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'wr_gen'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label='dcim')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, ts_dpsim_emt_vbr[name].values, label='vbr', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"wr_gen\"\n", + "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label=\"dcim\")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -165,10 +221,12 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'wr_gen'\n", - "rmse = ts_dpsim_emt_dcim[name].rmse(ts_dpsim_emt_dcim[name], ts_dpsim_emt_vbr[name].interpolate(timeStepDCIM))\n", + "name = \"wr_gen\"\n", + "rmse = ts_dpsim_emt_dcim[name].rmse(\n", + " ts_dpsim_emt_dcim[name], ts_dpsim_emt_vbr[name].interpolate(timeStepDCIM)\n", + ")\n", "print(rmse)\n", - "assert(rmse < 4e-4)" + "assert rmse < 4e-4" ] }, { @@ -186,15 +244,33 @@ "metadata": {}, "outputs": [], "source": [ - "name_exec = 'EMT_SynchronGenerator9OrderDCIM_LoadStep_TurbineGovernor_Exciter'\n", + "name_exec = \"EMT_SynchronGenerator9OrderDCIM_LoadStep_TurbineGovernor_Exciter\"\n", "\n", "model_name = name_exec\n", "\n", - "sim = subprocess.Popen([path_exec+name_exec, '--name', model_name, '--timestep', str(timeStepDCIM), '--duration', str(finalTime), '--option', 'WITHGOVERNOR=true', '--option', 'TIMESTEPEVENT='+str(loadStepEventTime), '--option', 'LOADFACTOR='+str(loadFactor)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timeStepDCIM),\n", + " \"--duration\",\n", + " str(finalTime),\n", + " \"--option\",\n", + " \"WITHGOVERNOR=true\",\n", + " \"--option\",\n", + " \"TIMESTEPEVENT=\" + str(loadStepEventTime),\n", + " \"--option\",\n", + " \"LOADFACTOR=\" + str(loadFactor),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt_dcim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -211,15 +287,33 @@ "metadata": {}, "outputs": [], "source": [ - "name_exec = 'EMT_SynchronGenerator9OrderVBR_LoadStep_TurbineGovernor_Exciter'\n", + "name_exec = \"EMT_SynchronGenerator9OrderVBR_LoadStep_TurbineGovernor_Exciter\"\n", "\n", "model_name = name_exec\n", "\n", - "sim = subprocess.Popen([path_exec+name_exec, '--name', model_name, '--timestep', str(timeStepVBR), '--duration', str(finalTime), '--option', 'WITHGOVERNOR=true', '--option', 'TIMESTEPEVENT='+str(loadStepEventTime), '--option', 'LOADFACTOR='+str(loadFactor)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timeStepVBR),\n", + " \"--duration\",\n", + " str(finalTime),\n", + " \"--option\",\n", + " \"WITHGOVERNOR=true\",\n", + " \"--option\",\n", + " \"TIMESTEPEVENT=\" + str(loadStepEventTime),\n", + " \"--option\",\n", + " \"LOADFACTOR=\" + str(loadFactor),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt_vbr = read_timeseries_csv(dpsim_result_file)" ] }, @@ -236,10 +330,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'v1_0'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt_dcim[name].values, label='dcim - with governor')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt_vbr[name].values, label='vbr - with governor', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"v1_0\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim - with governor\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr - with governor\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -257,10 +360,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'i_gen_0'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label='dcim - with governor')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, ts_dpsim_emt_vbr[name].values, label='vbr - with governor', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"i_gen_0\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim - with governor\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr - with governor\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -278,10 +390,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'wr_gen'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label='dcim - with governor')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, ts_dpsim_emt_vbr[name].values, label='vbr - with governor', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"wr_gen\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim - with governor\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr - with governor\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -299,10 +420,12 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'wr_gen'\n", - "rmse = ts_dpsim_emt_dcim[name].rmse(ts_dpsim_emt_dcim[name], ts_dpsim_emt_vbr[name].interpolate(timeStepDCIM))\n", + "name = \"wr_gen\"\n", + "rmse = ts_dpsim_emt_dcim[name].rmse(\n", + " ts_dpsim_emt_dcim[name], ts_dpsim_emt_vbr[name].interpolate(timeStepDCIM)\n", + ")\n", "print(rmse)\n", - "assert(rmse < 2.1e-5)" + "assert rmse < 2.1e-5" ] }, { @@ -320,15 +443,35 @@ "metadata": {}, "outputs": [], "source": [ - "name_exec = 'EMT_SynchronGenerator9OrderDCIM_LoadStep_TurbineGovernor_Exciter'\n", + "name_exec = \"EMT_SynchronGenerator9OrderDCIM_LoadStep_TurbineGovernor_Exciter\"\n", "\n", "model_name = name_exec\n", "\n", - "sim = subprocess.Popen([path_exec+name_exec, '--name', model_name, '--timestep', str(timeStepDCIM), '--duration', str(finalTime), '--option', 'WITHGOVERNOR=true', '--option', 'WITHEXCITER=true', '--option', 'TIMESTEPEVENT='+str(loadStepEventTime), '--option', 'LOADFACTOR='+str(loadFactor)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timeStepDCIM),\n", + " \"--duration\",\n", + " str(finalTime),\n", + " \"--option\",\n", + " \"WITHGOVERNOR=true\",\n", + " \"--option\",\n", + " \"WITHEXCITER=true\",\n", + " \"--option\",\n", + " \"TIMESTEPEVENT=\" + str(loadStepEventTime),\n", + " \"--option\",\n", + " \"LOADFACTOR=\" + str(loadFactor),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt_dcim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -345,15 +488,35 @@ "metadata": {}, "outputs": [], "source": [ - "name_exec = 'EMT_SynchronGenerator9OrderVBR_LoadStep_TurbineGovernor_Exciter'\n", + "name_exec = \"EMT_SynchronGenerator9OrderVBR_LoadStep_TurbineGovernor_Exciter\"\n", "\n", "model_name = name_exec\n", "\n", - "sim = subprocess.Popen([path_exec+name_exec, '--name', model_name, '--timestep', str(timeStepVBR), '--duration', str(finalTime), '--option', 'WITHGOVERNOR=true', '--option', 'WITHEXCITER=true', '--option', 'TIMESTEPEVENT='+str(loadStepEventTime), '--option', 'LOADFACTOR='+str(loadFactor)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " model_name,\n", + " \"--timestep\",\n", + " str(timeStepVBR),\n", + " \"--duration\",\n", + " str(finalTime),\n", + " \"--option\",\n", + " \"WITHGOVERNOR=true\",\n", + " \"--option\",\n", + " \"WITHEXCITER=true\",\n", + " \"--option\",\n", + " \"TIMESTEPEVENT=\" + str(loadStepEventTime),\n", + " \"--option\",\n", + " \"LOADFACTOR=\" + str(loadFactor),\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())\n", "\n", - "path = 'logs/' + model_name + '/'\n", - "dpsim_result_file = path + model_name + '.csv'\n", + "path = \"logs/\" + model_name + \"/\"\n", + "dpsim_result_file = path + model_name + \".csv\"\n", "ts_dpsim_emt_vbr = read_timeseries_csv(dpsim_result_file)" ] }, @@ -370,10 +533,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'v1_0'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt_dcim[name].values, label='dcim - with governor and exciter')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, PEAK1PH_TO_RMS3PH*ts_dpsim_emt_vbr[name].values, label='vbr - with governor and exciter', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"v1_0\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim - with governor and exciter\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " PEAK1PH_TO_RMS3PH * ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr - with governor and exciter\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -391,10 +563,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'i_gen_0'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label='dcim - with governor and exciter')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, ts_dpsim_emt_vbr[name].values, label='vbr - with governor and exciter', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"i_gen_0\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim - with governor and exciter\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr - with governor and exciter\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -412,10 +593,19 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "name = 'wr_gen'\n", - "plt.plot(ts_dpsim_emt_dcim[name].time, ts_dpsim_emt_dcim[name].values, label='dcim - with governor and exciter')\n", - "plt.plot(ts_dpsim_emt_vbr[name].time, ts_dpsim_emt_vbr[name].values, label='vbr - with governor and exciter', linestyle='--')\n", + "plt.figure(figsize=(12, 8))\n", + "name = \"wr_gen\"\n", + "plt.plot(\n", + " ts_dpsim_emt_dcim[name].time,\n", + " ts_dpsim_emt_dcim[name].values,\n", + " label=\"dcim - with governor and exciter\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_vbr[name].time,\n", + " ts_dpsim_emt_vbr[name].values,\n", + " label=\"vbr - with governor and exciter\",\n", + " linestyle=\"--\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -433,10 +623,12 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'wr_gen'\n", - "rmse = ts_dpsim_emt_dcim[name].rmse(ts_dpsim_emt_dcim[name], ts_dpsim_emt_vbr[name].interpolate(timeStepDCIM))\n", + "name = \"wr_gen\"\n", + "rmse = ts_dpsim_emt_dcim[name].rmse(\n", + " ts_dpsim_emt_dcim[name], ts_dpsim_emt_vbr[name].interpolate(timeStepDCIM)\n", + ")\n", "print(rmse)\n", - "assert(rmse < 8e-6)" + "assert rmse < 8e-6" ] } ], diff --git a/examples/Notebooks/Components/Trafo.ipynb b/examples/Notebooks/Components/Trafo.ipynb index e54a49a58c..5fa3908da4 100644 --- a/examples/Notebooks/Components/Trafo.ipynb +++ b/examples/Notebooks/Components/Trafo.ipynb @@ -23,7 +23,7 @@ "\n", "epsilon = 1e-12\n", "\n", - "PEAK1PH_TO_RMS3PH = np.sqrt(3/2)" + "PEAK1PH_TO_RMS3PH = np.sqrt(3 / 2)" ] }, { @@ -41,10 +41,10 @@ "source": [ "time_step = 0.00005\n", "final_time = 1\n", - "sim_name = 'SP_Trafo_Elements'\n", + "sim_name = \"SP_Trafo_Elements\"\n", "frequency = 50\n", "omega = 2 * np.pi * frequency\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "voltage_hv_side = 100000\n", "voltage_mv_side = 10000\n", @@ -55,22 +55,26 @@ "q_snub = dpsimpy.Q_SNUB_TRANSFORMER * trafo_power\n", "load_resistance_hv_side = 10000\n", "ratio = voltage_hv_side / voltage_mv_side\n", - "snubber_resistance_hv_side = np.abs(voltage_hv_side)**2 / p_snub\n", - "snubber_resistance_mv_side_to_hv_side = ratio**2 * np.abs(voltage_mv_side)**2 / p_snub\n", - "snubber_capacitance_mv_side_to_hv_side = 1/(omega * ratio**2 * np.abs(voltage_mv_side)**2 / q_snub) \n", + "snubber_resistance_hv_side = np.abs(voltage_hv_side) ** 2 / p_snub\n", + "snubber_resistance_mv_side_to_hv_side = ratio**2 * np.abs(voltage_mv_side) ** 2 / p_snub\n", + "snubber_capacitance_mv_side_to_hv_side = 1 / (\n", + " omega * ratio**2 * np.abs(voltage_mv_side) ** 2 / q_snub\n", + ")\n", "\n", - "n1 = dpsimpy.sp.SimNode('n1')\n", - "n2 = dpsimpy.sp.SimNode('n2')\n", - "vn1 = dpsimpy.sp.SimNode('vn1')\n", + "n1 = dpsimpy.sp.SimNode(\"n1\")\n", + "n2 = dpsimpy.sp.SimNode(\"n2\")\n", + "vn1 = dpsimpy.sp.SimNode(\"vn1\")\n", "gnd = dpsimpy.sp.SimNode.gnd\n", "\n", - "vs = dpsimpy.sp.ph1.VoltageSource('v_1')\n", - "trafo_res = dpsimpy.sp.ph1.Resistor('trafo_res')\n", - "trafo_snubber_res_hv_side = dpsimpy.sp.ph1.Resistor('trafo_snub_res_mv') ##FIXME: Is the naming correct here?\n", - "trafo_snubber_res_mv_side = dpsimpy.sp.ph1.Resistor('trafo_snub_res_hv')\n", - "trafo_snubber_cap_mv_side = dpsimpy.sp.ph1.Capacitor('trafo_snub_cap_mv')\n", - "trafo_ind = dpsimpy.sp.ph1.Inductor('trafo_ind')\n", - "load_res = dpsimpy.sp.ph1.Resistor('r_1')\n", + "vs = dpsimpy.sp.ph1.VoltageSource(\"v_1\")\n", + "trafo_res = dpsimpy.sp.ph1.Resistor(\"trafo_res\")\n", + "trafo_snubber_res_hv_side = dpsimpy.sp.ph1.Resistor(\n", + " \"trafo_snub_res_mv\"\n", + ") ##FIXME: Is the naming correct here?\n", + "trafo_snubber_res_mv_side = dpsimpy.sp.ph1.Resistor(\"trafo_snub_res_hv\")\n", + "trafo_snubber_cap_mv_side = dpsimpy.sp.ph1.Capacitor(\"trafo_snub_cap_mv\")\n", + "trafo_ind = dpsimpy.sp.ph1.Inductor(\"trafo_ind\")\n", + "load_res = dpsimpy.sp.ph1.Resistor(\"r_1\")\n", "\n", "vs.connect([gnd, n1])\n", "trafo_res.connect([n1, vn1])\n", @@ -88,12 +92,24 @@ "trafo_snubber_cap_mv_side.set_parameters(snubber_capacitance_mv_side_to_hv_side)\n", "load_res.set_parameters(load_resistance_hv_side)\n", "\n", - "sys = dpsimpy.SystemTopology(50, [n1, n2, vn1], [vs, trafo_res, trafo_ind, trafo_snubber_res_hv_side, trafo_snubber_res_mv_side, trafo_snubber_cap_mv_side, load_res])\n", + "sys = dpsimpy.SystemTopology(\n", + " 50,\n", + " [n1, n2, vn1],\n", + " [\n", + " vs,\n", + " trafo_res,\n", + " trafo_ind,\n", + " trafo_snubber_res_hv_side,\n", + " trafo_snubber_res_mv_side,\n", + " trafo_snubber_cap_mv_side,\n", + " load_res,\n", + " ],\n", + ")\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('v2', 'v', n2)\n", - "logger.log_attribute('itrafo', 'i_intf', trafo_ind)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"v2\", \"v\", n2)\n", + "logger.log_attribute(\"itrafo\", \"i_intf\", trafo_ind)\n", "\n", "sim = dpsimpy.Simulation(sim_name)\n", "sim.set_system(sys)\n", @@ -120,8 +136,8 @@ "source": [ "time_step = 0.00005\n", "final_time = 1\n", - "sim_name = 'SP_Trafo_Component'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"SP_Trafo_Component\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "voltage_hv_side = 100000\n", "voltage_mv_side = 10000\n", @@ -131,29 +147,38 @@ "ratio = voltage_hv_side / voltage_mv_side\n", "load_resistance_mv_side = load_resistance_hv_side / ratio**2\n", "\n", - "n1 = dpsimpy.sp.SimNode('n1')\n", - "n2 = dpsimpy.sp.SimNode('n2')\n", + "n1 = dpsimpy.sp.SimNode(\"n1\")\n", + "n2 = dpsimpy.sp.SimNode(\"n2\")\n", "gnd = dpsimpy.sp.SimNode.gnd\n", "\n", - "vs = dpsimpy.sp.ph1.VoltageSource('v_1', dpsimpy.LogLevel.debug)\n", - "trafo = dpsimpy.sp.ph1.Transformer('trafo', 'trafo', dpsimpy.LogLevel.debug, with_resistive_losses=True)\n", - "load_res = dpsimpy.sp.ph1.Resistor('r_1', dpsimpy.LogLevel.debug)\n", + "vs = dpsimpy.sp.ph1.VoltageSource(\"v_1\", dpsimpy.LogLevel.debug)\n", + "trafo = dpsimpy.sp.ph1.Transformer(\n", + " \"trafo\", \"trafo\", dpsimpy.LogLevel.debug, with_resistive_losses=True\n", + ")\n", + "load_res = dpsimpy.sp.ph1.Resistor(\"r_1\", dpsimpy.LogLevel.debug)\n", "\n", "vs.connect([gnd, n1])\n", "trafo.connect([n1, n2])\n", "load_res.connect([n2, gnd])\n", "\n", "vs.set_parameters(complex(voltage_hv_side, 0))\n", - "trafo.set_parameters(voltage_hv_side, voltage_mv_side, trafo_power, ratio, 0,\n", - " trafo_resistance, trafo_inductance)\n", + "trafo.set_parameters(\n", + " voltage_hv_side,\n", + " voltage_mv_side,\n", + " trafo_power,\n", + " ratio,\n", + " 0,\n", + " trafo_resistance,\n", + " trafo_inductance,\n", + ")\n", "load_res.set_parameters(load_resistance_mv_side)\n", "\n", "sys = dpsimpy.SystemTopology(50, [n1, n2], [vs, trafo, load_res])\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('v2', 'v', n2)\n", - "logger.log_attribute('itrafo', 'i_intf', trafo)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"v2\", \"v\", n2)\n", + "logger.log_attribute(\"itrafo\", \"i_intf\", trafo)\n", "\n", "sim = dpsimpy.Simulation(sim_name)\n", "sim.set_system(sys)\n", @@ -180,10 +205,10 @@ "source": [ "time_step = 0.00005\n", "final_time = 1\n", - "sim_name = 'DP_Trafo_Elements'\n", + "sim_name = \"DP_Trafo_Elements\"\n", "frequency = 50\n", "omega = 2 * np.pi * frequency\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "voltage_hv_side = 100000\n", "voltage_mv_side = 10000\n", @@ -194,22 +219,26 @@ "q_snub = dpsimpy.Q_SNUB_TRANSFORMER * trafo_power\n", "load_resistance_hv_side = 10000\n", "ratio = voltage_hv_side / voltage_mv_side\n", - "snubber_resistance_hv_side = np.abs(voltage_hv_side)**2 / p_snub\n", - "snubber_resistance_mv_side_to_hv_side = ratio**2 * np.abs(voltage_mv_side)**2 / p_snub\n", - "snubber_capacitance_mv_side_to_hv_side = 1/(omega * ratio**2 * np.abs(voltage_mv_side)**2 / q_snub) \n", + "snubber_resistance_hv_side = np.abs(voltage_hv_side) ** 2 / p_snub\n", + "snubber_resistance_mv_side_to_hv_side = ratio**2 * np.abs(voltage_mv_side) ** 2 / p_snub\n", + "snubber_capacitance_mv_side_to_hv_side = 1 / (\n", + " omega * ratio**2 * np.abs(voltage_mv_side) ** 2 / q_snub\n", + ")\n", "\n", - "n1 = dpsimpy.dp.SimNode('n1')\n", - "n2 = dpsimpy.dp.SimNode('n2')\n", - "vn1 = dpsimpy.dp.SimNode('vn1')\n", + "n1 = dpsimpy.dp.SimNode(\"n1\")\n", + "n2 = dpsimpy.dp.SimNode(\"n2\")\n", + "vn1 = dpsimpy.dp.SimNode(\"vn1\")\n", "gnd = dpsimpy.dp.SimNode.gnd\n", "\n", - "vs = dpsimpy.dp.ph1.VoltageSource('v_1')\n", - "trafo_res = dpsimpy.dp.ph1.Resistor('trafo_res')\n", - "trafo_snubber_res_hv_side = dpsimpy.dp.ph1.Resistor('trafo_snub_res_mv') ##FIXME: Is the naming correct here?\n", - "trafo_snubber_res_mv_side = dpsimpy.dp.ph1.Resistor('trafo_snub_res_hv')\n", - "trafo_snubber_cap_mv_side = dpsimpy.dp.ph1.Capacitor('trafo_snub_cap_mv')\n", - "trafo_ind = dpsimpy.dp.ph1.Inductor('trafo_ind')\n", - "load_res = dpsimpy.dp.ph1.Resistor('r_1')\n", + "vs = dpsimpy.dp.ph1.VoltageSource(\"v_1\")\n", + "trafo_res = dpsimpy.dp.ph1.Resistor(\"trafo_res\")\n", + "trafo_snubber_res_hv_side = dpsimpy.dp.ph1.Resistor(\n", + " \"trafo_snub_res_mv\"\n", + ") ##FIXME: Is the naming correct here?\n", + "trafo_snubber_res_mv_side = dpsimpy.dp.ph1.Resistor(\"trafo_snub_res_hv\")\n", + "trafo_snubber_cap_mv_side = dpsimpy.dp.ph1.Capacitor(\"trafo_snub_cap_mv\")\n", + "trafo_ind = dpsimpy.dp.ph1.Inductor(\"trafo_ind\")\n", + "load_res = dpsimpy.dp.ph1.Resistor(\"r_1\")\n", "\n", "vs.connect([gnd, n1])\n", "trafo_res.connect([n1, vn1])\n", @@ -227,12 +256,24 @@ "trafo_snubber_cap_mv_side.set_parameters(snubber_capacitance_mv_side_to_hv_side)\n", "load_res.set_parameters(load_resistance_hv_side)\n", "\n", - "sys = dpsimpy.SystemTopology(50, [n1, n2, vn1], [vs, trafo_res, trafo_ind, trafo_snubber_res_hv_side, trafo_snubber_res_mv_side, trafo_snubber_cap_mv_side, load_res])\n", + "sys = dpsimpy.SystemTopology(\n", + " 50,\n", + " [n1, n2, vn1],\n", + " [\n", + " vs,\n", + " trafo_res,\n", + " trafo_ind,\n", + " trafo_snubber_res_hv_side,\n", + " trafo_snubber_res_mv_side,\n", + " trafo_snubber_cap_mv_side,\n", + " load_res,\n", + " ],\n", + ")\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('v2', 'v', n2)\n", - "logger.log_attribute('itrafo', 'i_intf', trafo_ind)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"v2\", \"v\", n2)\n", + "logger.log_attribute(\"itrafo\", \"i_intf\", trafo_ind)\n", "\n", "sim = dpsimpy.Simulation(sim_name)\n", "sim.set_system(sys)\n", @@ -259,8 +300,8 @@ "source": [ "time_step = 0.00005\n", "final_time = 1\n", - "sim_name = 'DP_Trafo_Component'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"DP_Trafo_Component\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "voltage_hv_side = 100000\n", "voltage_mv_side = 10000\n", @@ -270,29 +311,38 @@ "ratio = voltage_hv_side / voltage_mv_side\n", "load_resistance_mv_side = load_resistance_hv_side / ratio**2\n", "\n", - "n1 = dpsimpy.dp.SimNode('n1')\n", - "n2 = dpsimpy.dp.SimNode('n2')\n", + "n1 = dpsimpy.dp.SimNode(\"n1\")\n", + "n2 = dpsimpy.dp.SimNode(\"n2\")\n", "gnd = dpsimpy.dp.SimNode.gnd\n", "\n", - "vs = dpsimpy.dp.ph1.VoltageSource('v_1', dpsimpy.LogLevel.debug)\n", - "trafo = dpsimpy.dp.ph1.Transformer('trafo', 'trafo', dpsimpy.LogLevel.debug, with_resistive_losses=True)\n", - "load_res = dpsimpy.dp.ph1.Resistor('r_1', dpsimpy.LogLevel.debug)\n", + "vs = dpsimpy.dp.ph1.VoltageSource(\"v_1\", dpsimpy.LogLevel.debug)\n", + "trafo = dpsimpy.dp.ph1.Transformer(\n", + " \"trafo\", \"trafo\", dpsimpy.LogLevel.debug, with_resistive_losses=True\n", + ")\n", + "load_res = dpsimpy.dp.ph1.Resistor(\"r_1\", dpsimpy.LogLevel.debug)\n", "\n", "vs.connect([gnd, n1])\n", "trafo.connect([n1, n2])\n", "load_res.connect([n2, gnd])\n", "\n", "vs.set_parameters(complex(voltage_hv_side, 0))\n", - "trafo.set_parameters(voltage_hv_side, voltage_mv_side, trafo_power, ratio, 0,\n", - " trafo_resistance, trafo_inductance)\n", + "trafo.set_parameters(\n", + " voltage_hv_side,\n", + " voltage_mv_side,\n", + " trafo_power,\n", + " ratio,\n", + " 0,\n", + " trafo_resistance,\n", + " trafo_inductance,\n", + ")\n", "load_res.set_parameters(load_resistance_mv_side)\n", "\n", "sys = dpsimpy.SystemTopology(50, [n1, n2], [vs, trafo, load_res])\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('v2', 'v', n2)\n", - "logger.log_attribute('itrafo', 'i_intf', trafo)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"v2\", \"v\", n2)\n", + "logger.log_attribute(\"itrafo\", \"i_intf\", trafo)\n", "\n", "sim = dpsimpy.Simulation(sim_name)\n", "sim.set_system(sys)\n", @@ -319,10 +369,10 @@ "source": [ "time_step = 0.00005\n", "final_time = 1\n", - "sim_name = 'EMT_Trafo_Elements'\n", + "sim_name = \"EMT_Trafo_Elements\"\n", "frequency = 50\n", "omega = 2 * np.pi * frequency\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "voltage_hv_side = 100000\n", "voltage_mv_side = 10000\n", @@ -333,23 +383,27 @@ "q_snub = dpsimpy.Q_SNUB_TRANSFORMER * trafo_power\n", "load_resistance_hv_side = 10000\n", "ratio = voltage_hv_side / voltage_mv_side\n", - "snubber_resistance_hv_side = np.abs(voltage_hv_side)**2 / p_snub\n", - "snubber_resistance_mv_side_to_hv_side = ratio**2 * np.abs(voltage_mv_side)**2 / p_snub\n", - "snubber_capacitance_mv_side_to_hv_side = 1/(omega * ratio**2 * np.abs(voltage_mv_side)**2 / q_snub) \n", + "snubber_resistance_hv_side = np.abs(voltage_hv_side) ** 2 / p_snub\n", + "snubber_resistance_mv_side_to_hv_side = ratio**2 * np.abs(voltage_mv_side) ** 2 / p_snub\n", + "snubber_capacitance_mv_side_to_hv_side = 1 / (\n", + " omega * ratio**2 * np.abs(voltage_mv_side) ** 2 / q_snub\n", + ")\n", "\n", "\n", - "n1 = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC)\n", - "n2 = dpsimpy.emt.SimNode('n2', dpsimpy.PhaseType.ABC)\n", - "vn1 = dpsimpy.emt.SimNode('vn1', dpsimpy.PhaseType.ABC)\n", + "n1 = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC)\n", + "n2 = dpsimpy.emt.SimNode(\"n2\", dpsimpy.PhaseType.ABC)\n", + "vn1 = dpsimpy.emt.SimNode(\"vn1\", dpsimpy.PhaseType.ABC)\n", "gnd = dpsimpy.emt.SimNode.gnd\n", "\n", - "vs = dpsimpy.emt.ph3.VoltageSource('v_1')\n", - "trafo_res = dpsimpy.emt.ph3.Resistor('trafo_res')\n", - "trafo_snubber_res_hv_side = dpsimpy.emt.ph3.Resistor('trafo_snub_res_mv') ##FIXME: Is the naming correct here?\n", - "trafo_snubber_res_mv_side = dpsimpy.emt.ph3.Resistor('trafo_snub_res_hv')\n", - "trafo_snubber_cap_mv_side = dpsimpy.emt.ph3.Capacitor('trafo_snub_cap_mv')\n", - "trafo_ind = dpsimpy.emt.ph3.Inductor('trafo_ind')\n", - "load_res = dpsimpy.emt.ph3.Resistor('r_1')\n", + "vs = dpsimpy.emt.ph3.VoltageSource(\"v_1\")\n", + "trafo_res = dpsimpy.emt.ph3.Resistor(\"trafo_res\")\n", + "trafo_snubber_res_hv_side = dpsimpy.emt.ph3.Resistor(\n", + " \"trafo_snub_res_mv\"\n", + ") ##FIXME: Is the naming correct here?\n", + "trafo_snubber_res_mv_side = dpsimpy.emt.ph3.Resistor(\"trafo_snub_res_hv\")\n", + "trafo_snubber_cap_mv_side = dpsimpy.emt.ph3.Capacitor(\"trafo_snub_cap_mv\")\n", + "trafo_ind = dpsimpy.emt.ph3.Inductor(\"trafo_ind\")\n", + "load_res = dpsimpy.emt.ph3.Resistor(\"r_1\")\n", "\n", "vs.connect([gnd, n1])\n", "trafo_res.connect([n1, vn1])\n", @@ -359,20 +413,50 @@ "trafo_snubber_cap_mv_side.connect([n2, gnd])\n", "load_res.connect([n2, gnd])\n", "\n", - "vs.set_parameters(dpsimpy.Math.single_phase_variable_to_three_phase(complex(voltage_hv_side, 0)), 50)\n", - "trafo_res.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_resistance))\n", - "trafo_ind.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_inductance))\n", - "trafo_snubber_res_hv_side.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(snubber_resistance_hv_side))\n", - "trafo_snubber_res_mv_side.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(snubber_resistance_mv_side_to_hv_side))\n", - "trafo_snubber_cap_mv_side.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(snubber_capacitance_mv_side_to_hv_side))\n", - "load_res.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(load_resistance_hv_side))\n", + "vs.set_parameters(\n", + " dpsimpy.Math.single_phase_variable_to_three_phase(complex(voltage_hv_side, 0)), 50\n", + ")\n", + "trafo_res.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_resistance)\n", + ")\n", + "trafo_ind.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_inductance)\n", + ")\n", + "trafo_snubber_res_hv_side.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(snubber_resistance_hv_side)\n", + ")\n", + "trafo_snubber_res_mv_side.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(\n", + " snubber_resistance_mv_side_to_hv_side\n", + " )\n", + ")\n", + "trafo_snubber_cap_mv_side.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(\n", + " snubber_capacitance_mv_side_to_hv_side\n", + " )\n", + ")\n", + "load_res.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(load_resistance_hv_side)\n", + ")\n", "\n", - "sys = dpsimpy.SystemTopology(50, [n1, n2, vn1], [vs, trafo_res, trafo_ind, trafo_snubber_res_hv_side, trafo_snubber_res_mv_side, trafo_snubber_cap_mv_side, load_res])\n", + "sys = dpsimpy.SystemTopology(\n", + " 50,\n", + " [n1, n2, vn1],\n", + " [\n", + " vs,\n", + " trafo_res,\n", + " trafo_ind,\n", + " trafo_snubber_res_hv_side,\n", + " trafo_snubber_res_mv_side,\n", + " trafo_snubber_cap_mv_side,\n", + " load_res,\n", + " ],\n", + ")\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('v2', 'v', n2)\n", - "logger.log_attribute('itrafo', 'i_intf', trafo_ind)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"v2\", \"v\", n2)\n", + "logger.log_attribute(\"itrafo\", \"i_intf\", trafo_ind)\n", "\n", "sim = dpsimpy.Simulation(sim_name)\n", "sim.set_system(sys)\n", @@ -399,8 +483,8 @@ "source": [ "time_step = 0.00005\n", "final_time = 1\n", - "sim_name = 'EMT_Trafo_Component'\n", - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"EMT_Trafo_Component\"\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "\n", "voltage_hv_side = 100000\n", "voltage_mv_side = 10000\n", @@ -410,30 +494,42 @@ "ratio = voltage_hv_side / voltage_mv_side\n", "load_resistance_mv_side = load_resistance_hv_side / ratio**2\n", "\n", - "n1 = dpsimpy.emt.SimNode('n1', dpsimpy.PhaseType.ABC)\n", - "n2 = dpsimpy.emt.SimNode('n2', dpsimpy.PhaseType.ABC)\n", + "n1 = dpsimpy.emt.SimNode(\"n1\", dpsimpy.PhaseType.ABC)\n", + "n2 = dpsimpy.emt.SimNode(\"n2\", dpsimpy.PhaseType.ABC)\n", "gnd = dpsimpy.emt.SimNode.gnd\n", "\n", - "vs = dpsimpy.emt.ph3.VoltageSource('v_1', dpsimpy.LogLevel.debug)\n", - "trafo = dpsimpy.emt.ph3.Transformer('trafo', 'trafo', dpsimpy.LogLevel.debug, with_resistive_losses=True)\n", - "load_res = dpsimpy.emt.ph3.Resistor('r_1', dpsimpy.LogLevel.debug)\n", + "vs = dpsimpy.emt.ph3.VoltageSource(\"v_1\", dpsimpy.LogLevel.debug)\n", + "trafo = dpsimpy.emt.ph3.Transformer(\n", + " \"trafo\", \"trafo\", dpsimpy.LogLevel.debug, with_resistive_losses=True\n", + ")\n", + "load_res = dpsimpy.emt.ph3.Resistor(\"r_1\", dpsimpy.LogLevel.debug)\n", "\n", "vs.connect([gnd, n1])\n", "trafo.connect([n1, n2])\n", "load_res.connect([n2, gnd])\n", "\n", - "vs.set_parameters(dpsimpy.Math.single_phase_variable_to_three_phase(complex(voltage_hv_side, 0)), 50)\n", - "trafo.set_parameters(voltage_hv_side, voltage_mv_side, trafo_power, ratio, 0,\n", + "vs.set_parameters(\n", + " dpsimpy.Math.single_phase_variable_to_three_phase(complex(voltage_hv_side, 0)), 50\n", + ")\n", + "trafo.set_parameters(\n", + " voltage_hv_side,\n", + " voltage_mv_side,\n", + " trafo_power,\n", + " ratio,\n", + " 0,\n", " dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_resistance),\n", - " dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_inductance))\n", - "load_res.set_parameters(dpsimpy.Math.single_phase_parameter_to_three_phase(load_resistance_mv_side))\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(trafo_inductance),\n", + ")\n", + "load_res.set_parameters(\n", + " dpsimpy.Math.single_phase_parameter_to_three_phase(load_resistance_mv_side)\n", + ")\n", "\n", "sys = dpsimpy.SystemTopology(50, [n1, n2], [vs, trafo, load_res])\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", - "logger.log_attribute('v1', 'v', n1)\n", - "logger.log_attribute('v2', 'v', n2)\n", - "logger.log_attribute('itrafo', 'i_intf', trafo)\n", + "logger.log_attribute(\"v1\", \"v\", n1)\n", + "logger.log_attribute(\"v2\", \"v\", n2)\n", + "logger.log_attribute(\"itrafo\", \"i_intf\", trafo)\n", "\n", "sim = dpsimpy.Simulation(sim_name)\n", "sim.set_system(sys)\n", @@ -451,10 +547,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/SP_Trafo_Elements/'\n", - "log_name = 'SP_Trafo_Elements'\n", - "print(work_dir + log_name + '.csv')\n", - "trafo_elements = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/SP_Trafo_Elements/\"\n", + "log_name = \"SP_Trafo_Elements\"\n", + "print(work_dir + log_name + \".csv\")\n", + "trafo_elements = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "trafo_elements_sp_shifted = ts.frequency_shift_list(trafo_elements, 50)" ] }, @@ -465,7 +561,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_elements_sp_shifted['v1_shift'].time, trafo_elements_sp_shifted['v1_shift'].values, label='v1_shift')\n", + "plt.plot(\n", + " trafo_elements_sp_shifted[\"v1_shift\"].time,\n", + " trafo_elements_sp_shifted[\"v1_shift\"].values,\n", + " label=\"v1_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -477,7 +577,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_elements_sp_shifted['itrafo_shift'].time, trafo_elements_sp_shifted['itrafo_shift'].values, label='itrafo_shift')\n", + "plt.plot(\n", + " trafo_elements_sp_shifted[\"itrafo_shift\"].time,\n", + " trafo_elements_sp_shifted[\"itrafo_shift\"].values,\n", + " label=\"itrafo_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -495,10 +599,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/SP_Trafo_Component/'\n", - "log_name = 'SP_Trafo_Component'\n", - "print(work_dir + log_name + '.csv')\n", - "trafo_component = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/SP_Trafo_Component/\"\n", + "log_name = \"SP_Trafo_Component\"\n", + "print(work_dir + log_name + \".csv\")\n", + "trafo_component = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "trafo_component_sp_shifted = ts.frequency_shift_list(trafo_component, 50)" ] }, @@ -509,7 +613,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_component_sp_shifted['v1_shift'].time, trafo_component_sp_shifted['v1_shift'].values, label='v1_shift')\n", + "plt.plot(\n", + " trafo_component_sp_shifted[\"v1_shift\"].time,\n", + " trafo_component_sp_shifted[\"v1_shift\"].values,\n", + " label=\"v1_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -521,7 +629,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_component_sp_shifted['itrafo_shift'].time, trafo_component_sp_shifted['itrafo_shift'].values, label='itrafo_shift')\n", + "plt.plot(\n", + " trafo_component_sp_shifted[\"itrafo_shift\"].time,\n", + " trafo_component_sp_shifted[\"itrafo_shift\"].values,\n", + " label=\"itrafo_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -540,8 +652,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in ['v1_shift', 'itrafo_shift']:\n", - " plt.plot(trafo_elements_sp_shifted[name].time, trafo_elements_sp_shifted[name].values - trafo_component_sp_shifted[name].values, label=name+'_error')\n", + "for name in [\"v1_shift\", \"itrafo_shift\"]:\n", + " plt.plot(\n", + " trafo_elements_sp_shifted[name].time,\n", + " trafo_elements_sp_shifted[name].values\n", + " - trafo_component_sp_shifted[name].values,\n", + " label=name + \"_error\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -560,9 +677,14 @@ "outputs": [], "source": [ "errors_sp_shifted = []\n", - "for name in ['v1_shift', 'itrafo_shift']:\n", - " errors_sp_shifted.append(np.absolute(trafo_elements_sp_shifted[name].values - trafo_component_sp_shifted[name].values).max())\n", - " print(name + ': ' + str(errors_sp_shifted[-1]))\n", + "for name in [\"v1_shift\", \"itrafo_shift\"]:\n", + " errors_sp_shifted.append(\n", + " np.absolute(\n", + " trafo_elements_sp_shifted[name].values\n", + " - trafo_component_sp_shifted[name].values\n", + " ).max()\n", + " )\n", + " print(name + \": \" + str(errors_sp_shifted[-1]))\n", "assert np.max(errors_sp_shifted) < epsilon" ] }, @@ -579,10 +701,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_Trafo_Elements/'\n", - "log_name = 'DP_Trafo_Elements'\n", - "print(work_dir + log_name + '.csv')\n", - "trafo_elements = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/DP_Trafo_Elements/\"\n", + "log_name = \"DP_Trafo_Elements\"\n", + "print(work_dir + log_name + \".csv\")\n", + "trafo_elements = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "trafo_elements_dp_shifted = ts.frequency_shift_list(trafo_elements, 50)" ] }, @@ -593,7 +715,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_elements_dp_shifted['v1_shift'].time, trafo_elements_dp_shifted['v1_shift'].values, label='v1_shift')\n", + "plt.plot(\n", + " trafo_elements_dp_shifted[\"v1_shift\"].time,\n", + " trafo_elements_dp_shifted[\"v1_shift\"].values,\n", + " label=\"v1_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -605,7 +731,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_elements_dp_shifted['itrafo_shift'].time, trafo_elements_dp_shifted['itrafo_shift'].values, label='itrafo_shift')\n", + "plt.plot(\n", + " trafo_elements_dp_shifted[\"itrafo_shift\"].time,\n", + " trafo_elements_dp_shifted[\"itrafo_shift\"].values,\n", + " label=\"itrafo_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -623,10 +753,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/DP_Trafo_Component/'\n", - "log_name = 'DP_Trafo_Component'\n", - "print(work_dir + log_name + '.csv')\n", - "trafo_component = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"logs/DP_Trafo_Component/\"\n", + "log_name = \"DP_Trafo_Component\"\n", + "print(work_dir + log_name + \".csv\")\n", + "trafo_component = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "trafo_component_dp_shifted = ts.frequency_shift_list(trafo_component, 50)" ] }, @@ -637,7 +767,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_component_dp_shifted['v1_shift'].time, trafo_component_dp_shifted['v1_shift'].values, label='v1_shift')\n", + "plt.plot(\n", + " trafo_component_dp_shifted[\"v1_shift\"].time,\n", + " trafo_component_dp_shifted[\"v1_shift\"].values,\n", + " label=\"v1_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -649,7 +783,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_component_dp_shifted['itrafo_shift'].time, trafo_component_dp_shifted['itrafo_shift'].values, label='itrafo_shift')\n", + "plt.plot(\n", + " trafo_component_dp_shifted[\"itrafo_shift\"].time,\n", + " trafo_component_dp_shifted[\"itrafo_shift\"].values,\n", + " label=\"itrafo_shift\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -668,8 +806,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in ['v1_shift', 'itrafo_shift']:\n", - " plt.plot(trafo_elements_dp_shifted[name].time, trafo_elements_dp_shifted[name].values - trafo_component_dp_shifted[name].values, label=name+'_error')\n", + "for name in [\"v1_shift\", \"itrafo_shift\"]:\n", + " plt.plot(\n", + " trafo_elements_dp_shifted[name].time,\n", + " trafo_elements_dp_shifted[name].values\n", + " - trafo_component_dp_shifted[name].values,\n", + " label=name + \"_error\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -688,9 +831,14 @@ "outputs": [], "source": [ "errors_dp_shifted = []\n", - "for name in ['v1_shift', 'itrafo_shift']:\n", - " errors_dp_shifted.append(np.absolute(trafo_elements_dp_shifted[name].values - trafo_component_dp_shifted[name].values).max())\n", - " print(name + ': ' + str(errors_dp_shifted[-1]))\n", + "for name in [\"v1_shift\", \"itrafo_shift\"]:\n", + " errors_dp_shifted.append(\n", + " np.absolute(\n", + " trafo_elements_dp_shifted[name].values\n", + " - trafo_component_dp_shifted[name].values\n", + " ).max()\n", + " )\n", + " print(name + \": \" + str(errors_dp_shifted[-1]))\n", "assert np.max(errors_dp_shifted) < epsilon" ] }, @@ -707,10 +855,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_Trafo_Elements/'\n", - "log_name = 'EMT_Trafo_Elements'\n", - "print(work_dir + log_name + '.csv')\n", - "trafo_elements_emt = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_Trafo_Elements/\"\n", + "log_name = \"EMT_Trafo_Elements\"\n", + "print(work_dir + log_name + \".csv\")\n", + "trafo_elements_emt = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -720,7 +868,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_elements_emt['v1_0'].time, PEAK1PH_TO_RMS3PH*trafo_elements_emt['v1_0'].values, label='v1_0')\n", + "plt.plot(\n", + " trafo_elements_emt[\"v1_0\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_elements_emt[\"v1_0\"].values,\n", + " label=\"v1_0\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -732,7 +884,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_elements_emt['itrafo_0'].time, PEAK1PH_TO_RMS3PH*trafo_elements_emt['itrafo_0'].values, label='itrafo_0')\n", + "plt.plot(\n", + " trafo_elements_emt[\"itrafo_0\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_elements_emt[\"itrafo_0\"].values,\n", + " label=\"itrafo_0\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -750,10 +906,10 @@ "metadata": {}, "outputs": [], "source": [ - "work_dir = 'logs/EMT_Trafo_Component/'\n", - "log_name = 'EMT_Trafo_Component'\n", - "print(work_dir + log_name + '.csv')\n", - "trafo_component_emt = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "work_dir = \"logs/EMT_Trafo_Component/\"\n", + "log_name = \"EMT_Trafo_Component\"\n", + "print(work_dir + log_name + \".csv\")\n", + "trafo_component_emt = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -763,9 +919,21 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_component_emt['v1_0'].time, PEAK1PH_TO_RMS3PH*trafo_component_emt['v1_0'].values, label='v1_0')\n", - "plt.plot(trafo_component_emt['v1_1'].time, PEAK1PH_TO_RMS3PH*trafo_component_emt['v1_1'].values, label='v1_1')\n", - "plt.plot(trafo_component_emt['v1_2'].time, PEAK1PH_TO_RMS3PH*trafo_component_emt['v1_2'].values, label='v1_2')\n", + "plt.plot(\n", + " trafo_component_emt[\"v1_0\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[\"v1_0\"].values,\n", + " label=\"v1_0\",\n", + ")\n", + "plt.plot(\n", + " trafo_component_emt[\"v1_1\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[\"v1_1\"].values,\n", + " label=\"v1_1\",\n", + ")\n", + "plt.plot(\n", + " trafo_component_emt[\"v1_2\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[\"v1_2\"].values,\n", + " label=\"v1_2\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -777,9 +945,21 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(trafo_component_emt['itrafo_0'].time, PEAK1PH_TO_RMS3PH*trafo_component_emt['itrafo_0'].values, label='itrafo_0')\n", - "plt.plot(trafo_component_emt['itrafo_1'].time, PEAK1PH_TO_RMS3PH*trafo_component_emt['itrafo_1'].values, label='itrafo_1')\n", - "plt.plot(trafo_component_emt['itrafo_2'].time, PEAK1PH_TO_RMS3PH*trafo_component_emt['itrafo_2'].values, label='itrafo_2')\n", + "plt.plot(\n", + " trafo_component_emt[\"itrafo_0\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[\"itrafo_0\"].values,\n", + " label=\"itrafo_0\",\n", + ")\n", + "plt.plot(\n", + " trafo_component_emt[\"itrafo_1\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[\"itrafo_1\"].values,\n", + " label=\"itrafo_1\",\n", + ")\n", + "plt.plot(\n", + " trafo_component_emt[\"itrafo_2\"].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[\"itrafo_2\"].values,\n", + " label=\"itrafo_2\",\n", + ")\n", "plt.legend()\n", "plt.show()" ] @@ -798,8 +978,12 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in ['v1_0', 'v1_1', 'v1_1', 'itrafo_0', 'itrafo_1', 'itrafo_2']:\n", - " plt.plot(trafo_elements_emt[name].time, trafo_elements_emt[name].values - trafo_component_emt[name].values, label=name+'_error')\n", + "for name in [\"v1_0\", \"v1_1\", \"v1_1\", \"itrafo_0\", \"itrafo_1\", \"itrafo_2\"]:\n", + " plt.plot(\n", + " trafo_elements_emt[name].time,\n", + " trafo_elements_emt[name].values - trafo_component_emt[name].values,\n", + " label=name + \"_error\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -818,9 +1002,13 @@ "outputs": [], "source": [ "errors_emt = []\n", - "for name in ['v1_0', 'v1_1', 'v1_1', 'itrafo_0', 'itrafo_1', 'itrafo_2']:\n", - " errors_emt.append(np.absolute(trafo_elements_emt[name].values - trafo_component_emt[name].values).max())\n", - " print(name + ': ' + str(errors_emt[-1]))\n", + "for name in [\"v1_0\", \"v1_1\", \"v1_1\", \"itrafo_0\", \"itrafo_1\", \"itrafo_2\"]:\n", + " errors_emt.append(\n", + " np.absolute(\n", + " trafo_elements_emt[name].values - trafo_component_emt[name].values\n", + " ).max()\n", + " )\n", + " print(name + \": \" + str(errors_emt[-1]))\n", "assert np.max(errors_emt) < epsilon" ] }, @@ -838,8 +1026,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in [('v1_shift', 'v1_shift')]:\n", - " plt.plot(trafo_component_sp_shifted[name[0]].time, trafo_component_sp_shifted[name[0]].values - trafo_component_dp_shifted[name[1]].values, label=name[0]+' (SP) vs. '+name[1]+' (DP)')\n", + "for name in [(\"v1_shift\", \"v1_shift\")]:\n", + " plt.plot(\n", + " trafo_component_sp_shifted[name[0]].time,\n", + " trafo_component_sp_shifted[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values,\n", + " label=name[0] + \" (SP) vs. \" + name[1] + \" (DP)\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -851,8 +1044,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in [('itrafo_shift', 'itrafo_shift')]:\n", - " plt.plot(trafo_component_sp_shifted[name[0]].time, trafo_component_sp_shifted[name[0]].values - trafo_component_dp_shifted[name[1]].values, label=name[0]+' (SP) vs. '+name[1]+' (DP)')\n", + "for name in [(\"itrafo_shift\", \"itrafo_shift\")]:\n", + " plt.plot(\n", + " trafo_component_sp_shifted[name[0]].time,\n", + " trafo_component_sp_shifted[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values,\n", + " label=name[0] + \" (SP) vs. \" + name[1] + \" (DP)\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -872,12 +1070,23 @@ "source": [ "compare_errors_abs = []\n", "compare_errors_rel = []\n", - "for name in [('v1_shift', 'v1_shift'), ('itrafo_shift', 'itrafo_shift')]:\n", - " compare_errors_abs.append(np.absolute(trafo_component_sp_shifted[name[0]].values - trafo_component_dp_shifted[name[1]].values).max())\n", - " compare_errors_rel.append(np.absolute(trafo_component_sp_shifted[name[0]].values - trafo_component_dp_shifted[name[1]].values).max()/trafo_component_dp_shifted[name[1]].values.max())\n", - " print(name[0]+' vs. '+name[1] + ' (abs): ' + str(compare_errors_abs[-1]))\n", - " print(name[0]+' vs. '+name[1] + ' (rel): ' + str(compare_errors_rel[-1]))\n", - "print('Max rel error: '+ '{:.2}'.format(np.max(compare_errors_rel)*100) +'%')\n", + "for name in [(\"v1_shift\", \"v1_shift\"), (\"itrafo_shift\", \"itrafo_shift\")]:\n", + " compare_errors_abs.append(\n", + " np.absolute(\n", + " trafo_component_sp_shifted[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values\n", + " ).max()\n", + " )\n", + " compare_errors_rel.append(\n", + " np.absolute(\n", + " trafo_component_sp_shifted[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values\n", + " ).max()\n", + " / trafo_component_dp_shifted[name[1]].values.max()\n", + " )\n", + " print(name[0] + \" vs. \" + name[1] + \" (abs): \" + str(compare_errors_abs[-1]))\n", + " print(name[0] + \" vs. \" + name[1] + \" (rel): \" + str(compare_errors_rel[-1]))\n", + "print(\"Max rel error: \" + \"{:.2}\".format(np.max(compare_errors_rel) * 100) + \"%\")\n", "assert np.max(compare_errors_rel) < 3e-1" ] }, @@ -895,8 +1104,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in [('v1_0', 'v1_shift')]:\n", - " plt.plot(trafo_component_emt[name[0]].time, PEAK1PH_TO_RMS3PH*trafo_component_emt[name[0]].values - trafo_component_dp_shifted[name[1]].values, label=name[0]+' vs. '+name[1])\n", + "for name in [(\"v1_0\", \"v1_shift\")]:\n", + " plt.plot(\n", + " trafo_component_emt[name[0]].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values,\n", + " label=name[0] + \" vs. \" + name[1],\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -908,8 +1122,13 @@ "outputs": [], "source": [ "plt.figure()\n", - "for name in [('itrafo_0', 'itrafo_shift')]:\n", - " plt.plot(trafo_component_emt[name[0]].time, PEAK1PH_TO_RMS3PH*trafo_component_emt[name[0]].values - trafo_component_dp_shifted[name[1]].values, label=name[0]+' vs. '+name[1])\n", + "for name in [(\"itrafo_0\", \"itrafo_shift\")]:\n", + " plt.plot(\n", + " trafo_component_emt[name[0]].time,\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values,\n", + " label=name[0] + \" vs. \" + name[1],\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -929,12 +1148,23 @@ "source": [ "compare_errors_abs = []\n", "compare_errors_rel = []\n", - "for name in [('v1_0', 'v1_shift'), ('itrafo_0', 'itrafo_shift')]:\n", - " compare_errors_abs.append(np.absolute(PEAK1PH_TO_RMS3PH*trafo_component_emt[name[0]].values - trafo_component_dp_shifted[name[1]].values).max())\n", - " compare_errors_rel.append(np.absolute(PEAK1PH_TO_RMS3PH*trafo_component_emt[name[0]].values - trafo_component_dp_shifted[name[1]].values).max()/trafo_component_dp_shifted[name[1]].values.max())\n", - " print(name[0]+' vs. '+name[1] + ' (abs): ' + str(compare_errors_abs[-1]))\n", - " print(name[0]+' vs. '+name[1] + ' (rel): ' + str(compare_errors_rel[-1]))\n", - "print('Max rel error: '+ '{:.2}'.format(np.max(compare_errors_rel)*100) +'%')\n", + "for name in [(\"v1_0\", \"v1_shift\"), (\"itrafo_0\", \"itrafo_shift\")]:\n", + " compare_errors_abs.append(\n", + " np.absolute(\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values\n", + " ).max()\n", + " )\n", + " compare_errors_rel.append(\n", + " np.absolute(\n", + " PEAK1PH_TO_RMS3PH * trafo_component_emt[name[0]].values\n", + " - trafo_component_dp_shifted[name[1]].values\n", + " ).max()\n", + " / trafo_component_dp_shifted[name[1]].values.max()\n", + " )\n", + " print(name[0] + \" vs. \" + name[1] + \" (abs): \" + str(compare_errors_abs[-1]))\n", + " print(name[0] + \" vs. \" + name[1] + \" (rel): \" + str(compare_errors_rel[-1]))\n", + "print(\"Max rel error: \" + \"{:.2}\".format(np.max(compare_errors_rel) * 100) + \"%\")\n", "assert np.max(compare_errors_rel) < 1e-4" ] } diff --git a/examples/Notebooks/Features/AsynchronousIO.ipynb b/examples/Notebooks/Features/AsynchronousIO.ipynb index 3fa5bca8b6..ea200e7f75 100644 --- a/examples/Notebooks/Features/AsynchronousIO.ipynb +++ b/examples/Notebooks/Features/AsynchronousIO.ipynb @@ -46,7 +46,7 @@ "n1 = dpsim.dp.Node(\"n1\")\n", "\n", "# Components\n", - "v1 = dpsim.dp.ph1.VoltageSource(\"v_1\", [gnd, n1], V_ref=complex(345,0))\n", + "v1 = dpsim.dp.ph1.VoltageSource(\"v_1\", [gnd, n1], V_ref=complex(345, 0))\n", "\n", "sys = dpsim.SystemTopology(50, [gnd, n1], [v1])" ] @@ -67,16 +67,18 @@ "source": [ "sims = []\n", "for i in range(1, 4):\n", - " sim = dpsim.RealTimeSimulation(\"async_demo_%d\" % i, sys, timestep=i*1e-3, duration=3*i+5, pbar=True)\n", + " sim = dpsim.RealTimeSimulation(\n", + " \"async_demo_%d\" % i, sys, timestep=i * 1e-3, duration=3 * i + 5, pbar=True\n", + " )\n", " sim.start()\n", - " \n", + "\n", " sims += [sim]\n", "\n", "for i in range(1, 6):\n", " print(\"Doing something different: %d\" % i)\n", " await asyncio.sleep(1)\n", - " \n", - "_ = await asyncio.wait([ s.wait(Event.done) for s in sims ])" + "\n", + "_ = await asyncio.wait([s.wait(Event.done) for s in sims])" ] } ], diff --git a/examples/Notebooks/Features/Graphviz.ipynb b/examples/Notebooks/Features/Graphviz.ipynb index ba068be3e3..1a15617761 100644 --- a/examples/Notebooks/Features/Graphviz.ipynb +++ b/examples/Notebooks/Features/Graphviz.ipynb @@ -48,18 +48,18 @@ "source": [ "# Nodes\n", "gnd = dpsim.dp.Node.GND()\n", - "n1 = dpsim.dp.Node(\"n1\")\n", - "n2 = dpsim.dp.Node(\"n2\")\n", - "n3 = dpsim.dp.Node(\"n3\")\n", - "n4 = dpsim.dp.Node(\"n4\")\n", + "n1 = dpsim.dp.Node(\"n1\")\n", + "n2 = dpsim.dp.Node(\"n2\")\n", + "n3 = dpsim.dp.Node(\"n3\")\n", + "n4 = dpsim.dp.Node(\"n4\")\n", "\n", "# Components\n", - "v1 = dpsim.dp.ph1.VoltageSource(\"v_1\", [gnd, n1], V_ref=complex(345,0))\n", - "r1 = dpsim.dp.ph1.Resistor(\"r1\", [n1, n2], R=5)\n", - "c1 = dpsim.dp.ph1.Capacitor(\"c_1\", [n2, gnd], C=0.002)\n", + "v1 = dpsim.dp.ph1.VoltageSource(\"v_1\", [gnd, n1], V_ref=complex(345, 0))\n", + "r1 = dpsim.dp.ph1.Resistor(\"r1\", [n1, n2], R=5)\n", + "c1 = dpsim.dp.ph1.Capacitor(\"c_1\", [n2, gnd], C=0.002)\n", "rL1 = dpsim.dp.ph1.Resistor(\"r_load1\", [n2, n4], R=6.4)\n", - "l1 = dpsim.dp.ph1.Inductor(\"l_1\", [n4, n3], L=0.186)\n", - "c2 = dpsim.dp.ph1.Capacitor(\"c_2\", [n3, gnd], C=0.002)\n", + "l1 = dpsim.dp.ph1.Inductor(\"l_1\", [n4, n3], L=0.186)\n", + "c2 = dpsim.dp.ph1.Capacitor(\"c_2\", [n3, gnd], C=0.002)\n", "rL2 = dpsim.dp.ph1.Resistor(\"r_load2\", [n3, gnd], R=150)\n", "\n", "sys = dpsim.SystemTopology(50, [gnd, n1, n2, n3, n4], [v1, r1, c1, rL1, l1, c2, rL2])" @@ -79,7 +79,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim = dpsim.Simulation('IdealVS_PiLine_RLC_1', sys, duration=20, timestep=0.0005)\n", + "sim = dpsim.Simulation(\"IdealVS_PiLine_RLC_1\", sys, duration=20, timestep=0.0005)\n", "await sim.simulate()" ] }, @@ -151,9 +151,9 @@ "from glob import glob\n", "\n", "# Adjust this path to the root of the DPsim repo\n", - "files = glob('../../CIM/WSCC-09_RX/*.xml')\n", + "files = glob(\"../../CIM/WSCC-09_RX/*.xml\")\n", "\n", - "dpsim.load_cim('WSCC_9bus', files)" + "dpsim.load_cim(\"WSCC_9bus\", files)" ] }, { diff --git a/examples/Notebooks/Features/Progressbars.ipynb b/examples/Notebooks/Features/Progressbars.ipynb index 41cddb9a27..ff762f6135 100644 --- a/examples/Notebooks/Features/Progressbars.ipynb +++ b/examples/Notebooks/Features/Progressbars.ipynb @@ -33,18 +33,18 @@ "\n", "# Nodes\n", "gnd = dpsim.dp.Node.GND()\n", - "n1 = dpsim.dp.Node(\"n1\")\n", - "n2 = dpsim.dp.Node(\"n2\")\n", - "n3 = dpsim.dp.Node(\"n3\")\n", - "n4 = dpsim.dp.Node(\"n4\")\n", + "n1 = dpsim.dp.Node(\"n1\")\n", + "n2 = dpsim.dp.Node(\"n2\")\n", + "n3 = dpsim.dp.Node(\"n3\")\n", + "n4 = dpsim.dp.Node(\"n4\")\n", "\n", "# Components\n", - "v1 = dpsim.dp.ph1.VoltageSource(\"v_1\", [gnd, n1], V_ref=complex(345,0))\n", - "r1 = dpsim.dp.ph1.Resistor(\"r1\", [n1, n2], R=5)\n", - "c1 = dpsim.dp.ph1.Capacitor(\"c_1\", [n2, gnd], C=0.002)\n", + "v1 = dpsim.dp.ph1.VoltageSource(\"v_1\", [gnd, n1], V_ref=complex(345, 0))\n", + "r1 = dpsim.dp.ph1.Resistor(\"r1\", [n1, n2], R=5)\n", + "c1 = dpsim.dp.ph1.Capacitor(\"c_1\", [n2, gnd], C=0.002)\n", "rL1 = dpsim.dp.ph1.Resistor(\"r_load1\", [n2, n4], R=6.4)\n", - "l1 = dpsim.dp.ph1.Inductor(\"l_1\", [n4, n3], L=0.186)\n", - "c2 = dpsim.dp.ph1.Capacitor(\"c_2\", [n3, gnd], C=0.002)\n", + "l1 = dpsim.dp.ph1.Inductor(\"l_1\", [n4, n3], L=0.186)\n", + "c2 = dpsim.dp.ph1.Capacitor(\"c_2\", [n3, gnd], C=0.002)\n", "rL2 = dpsim.dp.ph1.Resistor(\"r_load2\", [n3, gnd], R=150)\n", "\n", "sys = dpsim.SystemTopology(50, [gnd, n1, n2, n3, n4], [v1, r1, c1, rL1, l1, c2, rL2])\n", @@ -91,10 +91,12 @@ "source": [ "import asyncio\n", "\n", + "\n", "async def dummy():\n", - " for i in range(1,10):\n", + " for i in range(1, 10):\n", " await asyncio.sleep(1)\n", - " print('Doing something different:', i)\n", + " print(\"Doing something different:\", i)\n", + "\n", "\n", "sim2 = dpsim.Simulation(\"progress_demo2\", sys, duration=20, timestep=0.00005)\n", "sim2.show_progressbar()\n", diff --git a/examples/Notebooks/Features/RealtimeDatalogger.ipynb b/examples/Notebooks/Features/RealtimeDatalogger.ipynb new file mode 100644 index 0000000000..3548656b08 --- /dev/null +++ b/examples/Notebooks/Features/RealtimeDatalogger.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# In-memory logging for realtime applications" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " DPsim integrates a datalogger for realtime applications. It pre-allocates memory to run without writing to a file until the simulation is finished.\n", + "\n", + " For normal simulations it also increases the speed of the execution." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We start by defining a very simple simulation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import dpsimpy\n", + "\n", + "# Parameters\n", + "duration = 1\n", + "timestep = 0.001\n", + "name = \"ExampleDatalogger1\"\n", + "log_path = \"./logs/\" + name + \".csv\"\n", + "attributes = 4 # real and imaginary for a voltage and a currrent\n", + "\n", + "# Nodes\n", + "gnd = dpsimpy.dp.SimNode.gnd\n", + "n1 = dpsimpy.dp.SimNode(\"n1\")\n", + "\n", + "# Components\n", + "v1 = dpsimpy.dp.ph1.VoltageSource(\"v_1\")\n", + "v1.set_parameters(V_ref=complex(345, 0), f_src=50)\n", + "v1.connect([gnd, n1])\n", + "r1 = dpsimpy.dp.ph1.Resistor(\"r1\")\n", + "r1.connect([gnd, n1])\n", + "\n", + "sys = dpsimpy.SystemTopology(50, [gnd, n1], [v1, r1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We setup now a Realtime Datalogger" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "logger = dpsimpy.RealTimeDataLogger(log_path, duration, timestep)\n", + "logger.log_attribute(\"n1.v\", \"v\", n1)\n", + "logger.log_attribute(\"r1.i\", \"i_intf\", r1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we setup a simple simulation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sim = dpsimpy.RealTimeSimulation(name, dpsimpy.LogLevel.debug)\n", + "sim.set_system(sys)\n", + "sim.set_domain(dpsimpy.Domain.DP)\n", + "sim.set_time_step(timestep)\n", + "sim.set_final_time(duration)\n", + "sim.add_logger(logger)\n", + "sim.run(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check that all went good" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Read the CSV\n", + "df = pd.read_csv(log_path)\n", + "\n", + "# Expected dimensions\n", + "expected_rows = int(duration / timestep + 0.5) # timesteps + 1\n", + "expected_cols = 1 + attributes # time + attributes\n", + "\n", + "# Assertions\n", + "assert df.shape[0] == expected_rows, f\"Expected {expected_rows} rows, got {df.shape[0]}\"\n", + "assert (\n", + " df.shape[1] == expected_cols\n", + "), f\"Expected {expected_cols} columns, got {df.shape[1]}\"\n", + "\n", + "print(\"OK:\", df.shape)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + }, + "tests": { + "skip": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/Notebooks/Features/Widgets.ipynb b/examples/Notebooks/Features/Widgets.ipynb index 406e292a88..8f4ad91ca3 100644 --- a/examples/Notebooks/Features/Widgets.ipynb +++ b/examples/Notebooks/Features/Widgets.ipynb @@ -45,8 +45,8 @@ "outputs": [], "source": [ "gnd = dpsim.dp.Node.GND()\n", - "n1 = dpsim.dp.Node(\"n1\")\n", - "n2 = dpsim.dp.Node(\"n2\")\n", + "n1 = dpsim.dp.Node(\"n1\")\n", + "n2 = dpsim.dp.Node(\"n2\")\n", "\n", "cs = dpsim.dp.ph1.CurrentSource(\"cs\", [gnd, n1])\n", "r1 = dpsim.dp.ph1.Resistor(\"r_1\", [n1, gnd])\n", @@ -56,12 +56,12 @@ "\n", "sys = dpsim.SystemTopology(50, [gnd, n1, n2], [cs, r1, c1, l1, r2])\n", "sim = dpsim.Simulation(\"Widgets\", sys, duration=0.1)\n", - " \n", + "\n", "logger = dpsim.Logger(\"Widgets\")\n", - "logger.log_attribute(n1, \"v\") # v1\n", - "logger.log_attribute(n2, \"v\") # v2\n", - "logger.log_attribute(cs, \"i_intf\") # i12\n", - "logger.log_attribute(c1, \"i_intf\") # i34\n", + "logger.log_attribute(n1, \"v\") # v1\n", + "logger.log_attribute(n2, \"v\") # v2\n", + "logger.log_attribute(cs, \"i_intf\") # i12\n", + "logger.log_attribute(c1, \"i_intf\") # i34\n", "sim.add_logger(logger)" ] }, @@ -81,7 +81,7 @@ "source": [ "def simulate(dt, dur, pha, mag, r1_val, r2_val, l_val, c_val):\n", " sim.reset()\n", - " \n", + "\n", " sim.timestep = dt\n", " sim.final_time = dur\n", " cs.I_ref = cmath.rect(mag, pha)\n", @@ -89,13 +89,13 @@ " c1.C = c_val\n", " l1.L = l_val * 1e-3\n", " r2.R = r2_val * 1e-3\n", - " \n", + "\n", " sim.start()\n", " while sim.state != 9:\n", " time.sleep(0.001)\n", - " \n", - " results = rt.read_timeseries_dpsim('logs/Widgets.csv')\n", - " for l in [ 'n1.v', 'n2.v', 'cs.i_intf', 'c_1.i_intf' ]:\n", + "\n", + " results = rt.read_timeseries_dpsim(\"logs/Widgets.csv\")\n", + " for l in [\"n1.v\", \"n2.v\", \"cs.i_intf\", \"c_1.i_intf\"]:\n", " emt = results[l].frequency_shift(50)\n", " pt.plot_timeseries(1, emt)" ] @@ -125,19 +125,32 @@ "from ipywidgets import interact, interactive, fixed, interact_manual\n", "import ipywidgets as widgets\n", "\n", - "output = interactive(simulate,\n", - " dt = widgets.FloatText(description=\"Timestep [s]\", value=1e-3, min=1e-3, max=1),\n", - " dur = widgets.FloatText(description=\"Duration [s]\", value=0.5, min=0.001, max=4),\n", - " pha = widgets.FloatSlider(description=\"Phase [rad]\", min=-math.pi, max=math.pi, continuous_update=cu),\n", - " mag = widgets.FloatSlider(description=\"Magnitude [V]\", value=10, min=0, max=100, continuous_update=cu),\n", - " r1_val = widgets.FloatSlider(description=\"Resistance [Ohm]\", value=1, min=0.1, max=10, continuous_update=cu),\n", - " r2_val = widgets.FloatSlider(description=\"Resistance [Ohm]\", value=1, min=0.1, max=10, continuous_update=cu),\n", - " l_val = widgets.FloatSlider(description=\"Inductance [H]\", value=1, min=1, max=10, continuous_update=cu),\n", - " c_val = widgets.FloatSlider(description=\"Capactance [F]\", value=1, min=1, max=10, continuous_update=cu)\n", + "output = interactive(\n", + " simulate,\n", + " dt=widgets.FloatText(description=\"Timestep [s]\", value=1e-3, min=1e-3, max=1),\n", + " dur=widgets.FloatText(description=\"Duration [s]\", value=0.5, min=0.001, max=4),\n", + " pha=widgets.FloatSlider(\n", + " description=\"Phase [rad]\", min=-math.pi, max=math.pi, continuous_update=cu\n", + " ),\n", + " mag=widgets.FloatSlider(\n", + " description=\"Magnitude [V]\", value=10, min=0, max=100, continuous_update=cu\n", + " ),\n", + " r1_val=widgets.FloatSlider(\n", + " description=\"Resistance [Ohm]\", value=1, min=0.1, max=10, continuous_update=cu\n", + " ),\n", + " r2_val=widgets.FloatSlider(\n", + " description=\"Resistance [Ohm]\", value=1, min=0.1, max=10, continuous_update=cu\n", + " ),\n", + " l_val=widgets.FloatSlider(\n", + " description=\"Inductance [H]\", value=1, min=1, max=10, continuous_update=cu\n", + " ),\n", + " c_val=widgets.FloatSlider(\n", + " description=\"Capactance [F]\", value=1, min=1, max=10, continuous_update=cu\n", + " ),\n", ")\n", "\n", "last = output.children[-1]\n", - "last.layout.height = '400px'\n", + "last.layout.height = \"400px\"\n", "output" ] }, diff --git a/examples/Notebooks/Grids/CIGRE_MV_pf-interactive-dpsimpy.ipynb b/examples/Notebooks/Grids/CIGRE_MV_pf-interactive-dpsimpy.ipynb index d57879f5d2..2d19b22812 100644 --- a/examples/Notebooks/Grids/CIGRE_MV_pf-interactive-dpsimpy.ipynb +++ b/examples/Notebooks/Grids/CIGRE_MV_pf-interactive-dpsimpy.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -53,9 +55,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'CIGRE_MV'\n", + "name = \"CIGRE_MV\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)" + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")" ] }, { @@ -64,7 +68,7 @@ "metadata": {}, "outputs": [], "source": [ - "#system.render_to_file('CIGRE_MV.svg')\n", + "# system.render_to_file('CIGRE_MV.svg')\n", "system" ] }, @@ -83,7 +87,7 @@ "\n", "logger = dpsimpy.Logger(name)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node)\n", + " logger.log_attribute(node.name() + \".V\", \"v\", node)\n", "sim.add_logger(logger)" ] }, @@ -111,7 +115,9 @@ "metadata": {}, "outputs": [], "source": [ - "sim.get_idobj_attr('LOAD-I-10', 'P_pu').get() # The get method provides a reference to the underlying value" + "sim.get_idobj_attr(\n", + " \"LOAD-I-10\", \"P_pu\"\n", + ").get() # The get method provides a reference to the underlying value" ] }, { @@ -120,7 +126,9 @@ "metadata": {}, "outputs": [], "source": [ - "sim.get_idobj_attr('N10', 'v') # This also works because the Attribute returned by get_idobj_attr is printable" + "sim.get_idobj_attr(\n", + " \"N10\", \"v\"\n", + ") # This also works because the Attribute returned by get_idobj_attr is printable" ] }, { @@ -129,7 +137,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim.get_idobj_attr('L1-2', 'i_intf')" + "sim.get_idobj_attr(\"L1-2\", \"i_intf\")" ] }, { @@ -138,7 +146,9 @@ "metadata": {}, "outputs": [], "source": [ - "sim.get_idobj_attr('LOAD-I-10', 'P_pu').set(0.00128) # Setting values can be done using an attribute's set function" + "sim.get_idobj_attr(\"LOAD-I-10\", \"P_pu\").set(\n", + " 0.00128\n", + ") # Setting values can be done using an attribute's set function" ] }, { diff --git a/examples/Notebooks/Grids/CIGRE_MV_powerflow-dpsimpy.ipynb b/examples/Notebooks/Grids/CIGRE_MV_powerflow-dpsimpy.ipynb index 8f24793c3f..c52f3986d8 100644 --- a/examples/Notebooks/Grids/CIGRE_MV_powerflow-dpsimpy.ipynb +++ b/examples/Notebooks/Grids/CIGRE_MV_powerflow-dpsimpy.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -56,9 +58,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'CIGRE_MV'\n", + "name = \"CIGRE_MV\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "system" ] }, @@ -75,7 +79,7 @@ "\n", "logger = dpsimpy.Logger(name)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node);\n", + " logger.log_attribute(node.name() + \".V\", \"v\", node)\n", "sim.add_logger(logger)" ] }, @@ -101,14 +105,14 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/'\n", - "logName = 'CIGRE_MV'\n", - "dpsim_result_file = path + logName + '.csv'\n", + "path = \"logs/\"\n", + "logName = \"CIGRE_MV\"\n", + "dpsim_result_file = path + logName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)\n", "\n", "# Fix for dpsim naming - TODO: unify dpsim notation in log file and update villas-dataprocessing accordingly\n", - "for ts,values in ts_dpsim.items():\n", + "for ts, values in ts_dpsim.items():\n", " values.name = values.name[:-2]" ] }, @@ -125,16 +129,16 @@ "metadata": {}, "outputs": [], "source": [ - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Neplan/ReferenceGrids/CIGRE_MV.rlf'\n", - "neplan_result_file = 'reference-results/CIGRE_MV.rlf'\n", - "urllib.request.urlretrieve(url, neplan_result_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Neplan/ReferenceGrids/CIGRE_MV.rlf\"\n", + "neplan_result_file = \"reference-results/CIGRE_MV.rlf\"\n", + "urllib.request.urlretrieve(url, neplan_result_file)\n", "print(neplan_result_file)\n", "\n", "ts_NEPLAN = read_timeseries_NEPLAN_loadflow(neplan_result_file)\n", - "#print([ts_NEPLAN[i].name for i in range(len(ts_NEPLAN))])" + "# print([ts_NEPLAN[i].name for i in range(len(ts_NEPLAN))])" ] }, { @@ -150,15 +154,19 @@ "metadata": {}, "outputs": [], "source": [ - "net_name='CIGRE_MV_NoTap'\n", - "threshold=0.5\n", + "net_name = \"CIGRE_MV_NoTap\"\n", + "threshold = 0.5\n", "\n", - "ts_NEPLAN_standardized=validationtools.convert_neplan_to_standard_timeseries(ts_NEPLAN)\n", - "#print([ts_NEPLAN_standardized[i].name for i in range(len(ts_NEPLAN_standardized))])\n", - "ts_dpsim_standardized=validationtools.convert_dpsim_to_standard_timeseries(ts_dpsim)\n", - "#print([ts_dpsim_standardized[i].name for i in range(len(ts_dpsim_standardized))])\n", - "res_err=validationtools.compare_timeseries(ts_NEPLAN_standardized,ts_dpsim_standardized)\n", - "validationtools.assert_modelica_results(net_name,res_err,threshold)" + "ts_NEPLAN_standardized = validationtools.convert_neplan_to_standard_timeseries(\n", + " ts_NEPLAN\n", + ")\n", + "# print([ts_NEPLAN_standardized[i].name for i in range(len(ts_NEPLAN_standardized))])\n", + "ts_dpsim_standardized = validationtools.convert_dpsim_to_standard_timeseries(ts_dpsim)\n", + "# print([ts_dpsim_standardized[i].name for i in range(len(ts_dpsim_standardized))])\n", + "res_err = validationtools.compare_timeseries(\n", + " ts_NEPLAN_standardized, ts_dpsim_standardized\n", + ")\n", + "validationtools.assert_modelica_results(net_name, res_err, threshold)" ] } ], diff --git a/examples/Notebooks/Grids/CIGRE_MV_powerflow_profiles-dpsimpy.ipynb b/examples/Notebooks/Grids/CIGRE_MV_powerflow_profiles-dpsimpy.ipynb index 12f8040b25..913abd2db3 100644 --- a/examples/Notebooks/Grids/CIGRE_MV_powerflow_profiles-dpsimpy.ipynb +++ b/examples/Notebooks/Grids/CIGRE_MV_powerflow_profiles-dpsimpy.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -46,13 +48,37 @@ "source": [ "import os\n", "\n", - "profiles = ['Load_H_1','Load_H_3','Load_H_4','Load_H_5','Load_H_6','Load_H_8','Load_H_10','Load_H_11','Load_H_12','Load_H_14','Load_I_1','Load_I_3','Load_I_7','Load_I_9','Load_I_10','Load_I_12','Load_I_13','Load_I_14']\n", + "profiles = [\n", + " \"Load_H_1\",\n", + " \"Load_H_3\",\n", + " \"Load_H_4\",\n", + " \"Load_H_5\",\n", + " \"Load_H_6\",\n", + " \"Load_H_8\",\n", + " \"Load_H_10\",\n", + " \"Load_H_11\",\n", + " \"Load_H_12\",\n", + " \"Load_H_14\",\n", + " \"Load_I_1\",\n", + " \"Load_I_3\",\n", + " \"Load_I_7\",\n", + " \"Load_I_9\",\n", + " \"Load_I_10\",\n", + " \"Load_I_12\",\n", + " \"Load_I_13\",\n", + " \"Load_I_14\",\n", + "]\n", "for profile in profiles:\n", - " filename = './profiles/'+profile+'.csv'\n", + " filename = \"./profiles/\" + profile + \".csv\"\n", " os.makedirs(os.path.dirname(filename), exist_ok=True)\n", - " download_grid_data(filename, 'https://raw.githubusercontent.com/dpsim-simulator/example-profile-data/master/CIGRE_MV_NoTap/load_profiles/'+profile+'.csv')\n", - " \n", - "profile_files = glob.glob('profiles/Load*.csv')\n", + " download_grid_data(\n", + " filename,\n", + " \"https://raw.githubusercontent.com/dpsim-simulator/example-profile-data/master/CIGRE_MV_NoTap/load_profiles/\"\n", + " + profile\n", + " + \".csv\",\n", + " )\n", + "\n", + "profile_files = glob.glob(\"profiles/Load*.csv\")\n", "print(profile_files)" ] }, @@ -64,7 +90,7 @@ "source": [ "import pathlib\n", "\n", - "profile_path = str(pathlib.Path().resolve())+'/profiles/'\n", + "profile_path = str(pathlib.Path().resolve()) + \"/profiles/\"\n", "print(profile_path)" ] }, @@ -86,9 +112,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'CIGRE-MV-Profiles'\n", + "name = \"CIGRE-MV-Profiles\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)" + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")" ] }, { @@ -97,25 +125,25 @@ "metadata": {}, "outputs": [], "source": [ - "assignList = { }\n", - "assignList['LOAD-H-1'] = 'Load_H_1'\n", - "assignList['LOAD-H-3'] = 'Load_H_3'\n", - "assignList['LOAD-H-4'] = 'Load_H_4'\n", - "assignList['LOAD-H-5'] = 'Load_H_5'\n", - "assignList['LOAD-H-6'] = 'Load_H_6'\n", - "assignList['LOAD-H-8'] = 'Load_H_8'\n", - "assignList['LOAD-H-10'] = 'Load_H_10'\n", - "assignList['LOAD-H-11'] = 'Load_H_11'\n", - "assignList['LOAD-H-12'] = 'Load_H_12'\n", - "assignList['LOAD-H-14'] = 'Load_H_14'\n", - "assignList['LOAD-I-1'] = 'Load_I_1'\n", - "assignList['LOAD-I-3'] = 'Load_I_3'\n", - "assignList['LOAD-I-7'] = 'Load_I_7'\n", - "assignList['LOAD-I-9'] = 'Load_I_9'\n", - "assignList['LOAD-I-10'] = 'Load_I_10'\n", - "assignList['LOAD-I-12'] = 'Load_I_12'\n", - "assignList['LOAD-I-13'] = 'Load_I_13'\n", - "assignList['LOAD-I-14'] = 'Load_I_14'" + "assignList = {}\n", + "assignList[\"LOAD-H-1\"] = \"Load_H_1\"\n", + "assignList[\"LOAD-H-3\"] = \"Load_H_3\"\n", + "assignList[\"LOAD-H-4\"] = \"Load_H_4\"\n", + "assignList[\"LOAD-H-5\"] = \"Load_H_5\"\n", + "assignList[\"LOAD-H-6\"] = \"Load_H_6\"\n", + "assignList[\"LOAD-H-8\"] = \"Load_H_8\"\n", + "assignList[\"LOAD-H-10\"] = \"Load_H_10\"\n", + "assignList[\"LOAD-H-11\"] = \"Load_H_11\"\n", + "assignList[\"LOAD-H-12\"] = \"Load_H_12\"\n", + "assignList[\"LOAD-H-14\"] = \"Load_H_14\"\n", + "assignList[\"LOAD-I-1\"] = \"Load_I_1\"\n", + "assignList[\"LOAD-I-3\"] = \"Load_I_3\"\n", + "assignList[\"LOAD-I-7\"] = \"Load_I_7\"\n", + "assignList[\"LOAD-I-9\"] = \"Load_I_9\"\n", + "assignList[\"LOAD-I-10\"] = \"Load_I_10\"\n", + "assignList[\"LOAD-I-12\"] = \"Load_I_12\"\n", + "assignList[\"LOAD-I-13\"] = \"Load_I_13\"\n", + "assignList[\"LOAD-I-14\"] = \"Load_I_14\"" ] }, { @@ -125,7 +153,9 @@ "outputs": [], "source": [ "csvreader = dpsimpy.CSVReader(name, profile_path, assignList, dpsimpy.LogLevel.info)\n", - "csvreader.assignLoadProfile(system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS)" + "csvreader.assignLoadProfile(\n", + " system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS\n", + ")" ] }, { @@ -152,7 +182,7 @@ "\n", "logger = dpsimpy.Logger(name)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node);\n", + " logger.log_attribute(node.name() + \".V\", \"v\", node)\n", "sim.add_logger(logger)" ] }, diff --git a/examples/Notebooks/Grids/DP_CIGRE_MV_withDG.ipynb b/examples/Notebooks/Grids/DP_CIGRE_MV_withDG.ipynb index 6b8b94907c..accb1eac8e 100644 --- a/examples/Notebooks/Grids/DP_CIGRE_MV_withDG.ipynb +++ b/examples/Notebooks/Grids/DP_CIGRE_MV_withDG.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -59,7 +61,7 @@ "time_step = 1e-3\n", "final_time = 3.0\n", "steady_state_init = False\n", - "sim_name = 'DP_CIGRE_MV_withDG'\n", + "sim_name = \"DP_CIGRE_MV_withDG\"\n", "sim_name_pf = sim_name + \"_Powerflow\"" ] }, @@ -76,30 +78,64 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system_pf = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_pf = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_pf.node('N' + str(n))\n", - " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0, resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_pf.node(\"N\" + str(n))\n", + " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_pf.add(pv)\n", " system_pf.connect_component(pv, [connection_node])\n", "\n", "\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", - " logger_pf.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_pf.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -111,7 +147,7 @@ "sim_pf.do_init_from_nodes_and_terminals(True)\n", "\n", "sim_pf.add_logger(logger_pf)\n", - "sim_pf.run()\n" + "sim_pf.run()" ] }, { @@ -127,67 +163,107 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader2 = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.debug)\n", - "system_dp = reader2.loadCIM(50, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_dp = reader2.loadCIM(\n", + " 50, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "\n", "pv_active_power = 50e3 * int(int(4319.1e3 * 1 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_dp.node('N' + str(n))\n", - " pv = dpsimpy.dp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_dp.node(\"N\" + str(n))\n", + " pv = dpsimpy.dp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_dp.add(pv)\n", " system_dp.connect_component(pv, [connection_node])\n", "\n", "system_dp.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", "\n", "# log node voltages\n", - "logger_dp= dpsimpy.Logger(sim_name)\n", + "logger_dp = dpsimpy.Logger(sim_name)\n", "for node in system_dp.nodes:\n", - " logger_dp.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_dp.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "# log line and load currents\n", "for comp in system_dp.components:\n", " if isinstance(comp, dpsimpy.dp.ph1.PiLine):\n", - " logger_dp.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_dp.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", " if isinstance(comp, dpsimpy.dp.ph1.RXLoad):\n", - " logger_dp.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_dp.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", "\n", "# log output of PV connected at N11\n", - "pv_name = 'pv_N11'\n", + "pv_name = \"pv_N11\"\n", "pv = system_dp.component(pv_name)\n", "input_names = [\n", - " \"pv_powerctrl_input_pref\", \"pv_powerctrl_input_qref\", \"pv_powerctrl_input_vcd\",\n", - " \"pv_powerctrl_input_vcq\", \"pv_powerctrl_input_ircd\", \"pv_powerctrl_input_ircq\"\n", + " \"pv_powerctrl_input_pref\",\n", + " \"pv_powerctrl_input_qref\",\n", + " \"pv_powerctrl_input_vcd\",\n", + " \"pv_powerctrl_input_vcq\",\n", + " \"pv_powerctrl_input_ircd\",\n", + " \"pv_powerctrl_input_ircq\",\n", "]\n", - "logger_dp.log_attribute(input_names, 'powerctrl_inputs', pv)\n", + "logger_dp.log_attribute(input_names, \"powerctrl_inputs\", pv)\n", "\n", "state_names = [\n", - " \"pv_powerctrl_state_p\", \"pv_powerctrl_state_q\", \"pv_powerctrl_state_phid\",\n", - " \"pv_powerctrl_state_phiq\", \"pv_powerctrl_state_gammad\", \"pv_powerctrl_state_gammaq\"\n", + " \"pv_powerctrl_state_p\",\n", + " \"pv_powerctrl_state_q\",\n", + " \"pv_powerctrl_state_phid\",\n", + " \"pv_powerctrl_state_phiq\",\n", + " \"pv_powerctrl_state_gammad\",\n", + " \"pv_powerctrl_state_gammaq\",\n", "]\n", - "logger_dp.log_attribute(state_names, 'powerctrl_states', pv)\n", + "logger_dp.log_attribute(state_names, \"powerctrl_states\", pv)\n", "\n", - "output_names = [\n", - " \"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"\n", - "]\n", + "output_names = [\"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"]\n", "\n", - "logger_dp.log_attribute(output_names, 'powerctrl_outputs', pv)\n", + "logger_dp.log_attribute(output_names, \"powerctrl_outputs\", pv)\n", "\n", - "logger_dp.log_attribute(pv_name + '_v_intf', 'v_intf', pv)\n", - "logger_dp.log_attribute(pv_name + '_i_intf', 'i_intf', pv)\n", - "logger_dp.log_attribute(pv_name + '_pll_output', 'pll_output', pv)\n", - "logger_dp.log_attribute(pv_name + '_vsref', 'Vsref', pv)\n", - "logger_dp.log_attribute(pv_name + '_vs', 'Vs', pv)\n", + "logger_dp.log_attribute(pv_name + \"_v_intf\", \"v_intf\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_i_intf\", \"i_intf\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_pll_output\", \"pll_output\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_vsref\", \"Vsref\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_vs\", \"Vs\", pv)\n", "\n", "sim_dp = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", "sim_dp.set_system(system_dp)\n", @@ -222,10 +298,9 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "modelName = 'DP_CIGRE_MV_withDG_Powerflow'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"DP_CIGRE_MV_withDG_Powerflow\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim_powerflow = read_timeseries_csv(dpsim_result_file)" ] @@ -243,9 +318,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -264,8 +339,14 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -281,9 +362,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'DP_CIGRE_MV_withDG'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"DP_CIGRE_MV_withDG\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -301,9 +382,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V' and ts_name[-2:] == '.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\" and ts_name[-2:] == \".V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -322,9 +403,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.V':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".V\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -340,9 +427,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.V':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".V\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -365,9 +458,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-7:]=='state_p' or ts_name[-7:]=='state_q':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-7:] == \"state_p\" or ts_name[-7:] == \"state_q\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -386,9 +479,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-7:]!='state_p' and ts_name[-7:]!='state_q' and 'state' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-7:] != \"state_p\" and ts_name[-7:] != \"state_q\" and \"state\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -407,9 +500,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'state' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"state\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -425,9 +524,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'state' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"state\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -443,9 +548,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -464,9 +569,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -482,9 +593,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -500,9 +617,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -521,9 +638,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -539,9 +662,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -557,9 +686,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -578,12 +707,14 @@ "metadata": {}, "outputs": [], "source": [ - "pv_N11_s_intf = ts_dpsim['pv_N11_v_intf'].values*np.conj(ts_dpsim['pv_N11_i_intf'].values)\n", - "plt.figure(figsize=(12,6))\n", - "plt.plot(ts_dpsim['pv_N11_v_intf'].time, np.real(pv_N11_s_intf), label='pv_N11_P_intf')\n", - "plt.plot(ts_dpsim['pv_N11_v_intf'].time, np.imag(pv_N11_s_intf), label='pv_N11_Q_intf')\n", + "pv_N11_s_intf = ts_dpsim[\"pv_N11_v_intf\"].values * np.conj(\n", + " ts_dpsim[\"pv_N11_i_intf\"].values\n", + ")\n", + "plt.figure(figsize=(12, 6))\n", + "plt.plot(ts_dpsim[\"pv_N11_v_intf\"].time, np.real(pv_N11_s_intf), label=\"pv_N11_P_intf\")\n", + "plt.plot(ts_dpsim[\"pv_N11_v_intf\"].time, np.imag(pv_N11_s_intf), label=\"pv_N11_Q_intf\")\n", "plt.legend()\n", - "plt.show()\n" + "plt.show()" ] }, { @@ -599,10 +730,22 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))\n", - "print('pv_N11_s_intf' + ': ' + str(np.real(pv_N11_s_intf[0])) + ', ' + str(np.imag(pv_N11_s_intf[0])))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )\n", + "print(\n", + " \"pv_N11_s_intf\"\n", + " + \": \"\n", + " + str(np.real(pv_N11_s_intf[0]))\n", + " + \", \"\n", + " + str(np.imag(pv_N11_s_intf[0]))\n", + ")" ] }, { @@ -618,10 +761,22 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))\n", - "print('pv_N11_s_intf' + ': ' + str(np.real(pv_N11_s_intf[-1])) + ', ' + str(np.imag(pv_N11_s_intf[-1])))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )\n", + "print(\n", + " \"pv_N11_s_intf\"\n", + " + \": \"\n", + " + str(np.real(pv_N11_s_intf[-1]))\n", + " + \", \"\n", + " + str(np.imag(pv_N11_s_intf[-1]))\n", + ")" ] } ], diff --git a/examples/Notebooks/Grids/DP_CIGRE_MV_withDG_withLoadStep.ipynb b/examples/Notebooks/Grids/DP_CIGRE_MV_withDG_withLoadStep.ipynb index 4a52e83914..a0e8df8bfd 100644 --- a/examples/Notebooks/Grids/DP_CIGRE_MV_withDG_withLoadStep.ipynb +++ b/examples/Notebooks/Grids/DP_CIGRE_MV_withDG_withLoadStep.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -51,7 +53,7 @@ "source": [ "time_step = 1e-3\n", "final_time = 3.0\n", - "sim_name = 'DP_CIGRE_MV_withDG_withLoadStep'\n", + "sim_name = \"DP_CIGRE_MV_withDG_withLoadStep\"\n", "sim_name_pf = sim_name + \"_Powerflow\"" ] }, @@ -68,30 +70,64 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system_pf = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_pf = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_pf.node('N' + str(n))\n", - " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_pf.node(\"N\" + str(n))\n", + " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_pf.add(pv)\n", " system_pf.connect_component(pv, [connection_node])\n", "\n", "\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", - " logger_pf.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_pf.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -103,7 +139,7 @@ "sim_pf.do_init_from_nodes_and_terminals(True)\n", "\n", "sim_pf.add_logger(logger_pf)\n", - "sim_pf.run()\n" + "sim_pf.run()" ] }, { @@ -119,78 +155,120 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader2 = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.debug)\n", - "system_dp = reader2.loadCIM(50, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_dp = reader2.loadCIM(\n", + " 50, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_dp.node('N' + str(n))\n", - " pv = dpsimpy.dp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_dp.node(\"N\" + str(n))\n", + " pv = dpsimpy.dp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_dp.add(pv)\n", " system_dp.connect_component(pv, [connection_node])\n", "\n", "system_dp.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", "\n", "# log node voltages\n", - "logger_dp= dpsimpy.Logger(sim_name)\n", + "logger_dp = dpsimpy.Logger(sim_name)\n", "for node in system_dp.nodes:\n", - " logger_dp.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_dp.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "# log line and load currents\n", "for comp in system_dp.components:\n", " if isinstance(comp, dpsimpy.dp.ph1.PiLine):\n", - " logger_dp.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_dp.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", " if isinstance(comp, dpsimpy.dp.ph1.RXLoad):\n", - " logger_dp.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_dp.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", "\n", "# log output of PV connected at N11\n", - "pv_name = 'pv_N11'\n", + "pv_name = \"pv_N11\"\n", "pv = system_dp.component(pv_name)\n", "input_names = [\n", - " \"pv_powerctrl_input_pref\", \"pv_powerctrl_input_qref\", \"pv_powerctrl_input_vcd\",\n", - " \"pv_powerctrl_input_vcq\", \"pv_powerctrl_input_ircd\", \"pv_powerctrl_input_ircq\"\n", + " \"pv_powerctrl_input_pref\",\n", + " \"pv_powerctrl_input_qref\",\n", + " \"pv_powerctrl_input_vcd\",\n", + " \"pv_powerctrl_input_vcq\",\n", + " \"pv_powerctrl_input_ircd\",\n", + " \"pv_powerctrl_input_ircq\",\n", "]\n", - "logger_dp.log_attribute(input_names, 'powerctrl_inputs', pv)\n", + "logger_dp.log_attribute(input_names, \"powerctrl_inputs\", pv)\n", "\n", "state_names = [\n", - " \"pv_powerctrl_state_p\", \"pv_powerctrl_state_q\", \"pv_powerctrl_state_phid\",\n", - " \"pv_powerctrl_state_phiq\", \"pv_powerctrl_state_gammad\", \"pv_powerctrl_state_gammaq\"\n", + " \"pv_powerctrl_state_p\",\n", + " \"pv_powerctrl_state_q\",\n", + " \"pv_powerctrl_state_phid\",\n", + " \"pv_powerctrl_state_phiq\",\n", + " \"pv_powerctrl_state_gammad\",\n", + " \"pv_powerctrl_state_gammaq\",\n", "]\n", - "logger_dp.log_attribute(state_names, 'powerctrl_states', pv)\n", + "logger_dp.log_attribute(state_names, \"powerctrl_states\", pv)\n", "\n", - "output_names = [\n", - " \"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"\n", - "]\n", + "output_names = [\"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"]\n", "\n", - "logger_dp.log_attribute(output_names, 'powerctrl_outputs', pv)\n", + "logger_dp.log_attribute(output_names, \"powerctrl_outputs\", pv)\n", "\n", - "logger_dp.log_attribute(pv_name + '_v_intf', 'v_intf', pv)\n", - "logger_dp.log_attribute(pv_name + '_i_intf', 'i_intf', pv)\n", - "logger_dp.log_attribute(pv_name + '_pll_output', 'pll_output', pv)\n", - "logger_dp.log_attribute(pv_name + '_vsref', 'Vsref', pv)\n", - "logger_dp.log_attribute(pv_name + '_vs', 'Vs', pv)\n", + "logger_dp.log_attribute(pv_name + \"_v_intf\", \"v_intf\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_i_intf\", \"i_intf\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_pll_output\", \"pll_output\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_vsref\", \"Vsref\", pv)\n", + "logger_dp.log_attribute(pv_name + \"_vs\", \"Vs\", pv)\n", "\n", "# load step sized in absolute terms\n", "load_switch = dpsimpy.dp.ph1.Switch(\"Load_Add_Switch_N11\", dpsimpy.LogLevel.debug)\n", - "connection_node = system_dp.node('N11')\n", - "resistance = np.abs(connection_node.initial_single_voltage())**2 / 1500.0e3\n", + "connection_node = system_dp.node(\"N11\")\n", + "resistance = np.abs(connection_node.initial_single_voltage()) ** 2 / 1500.0e3\n", "load_switch.set_parameters(1e9, resistance)\n", "load_switch.open()\n", "system_dp.add(load_switch)\n", - "system_dp.connect_component(load_switch, [dpsimpy.dp.SimNode.gnd, system_dp.node('N11')])\n", - "logger_dp.log_attribute('switchedload_i', 'i_intf', load_switch)\n", - "load_step_event = dpsimpy.event.SwitchEvent(2 - time_step, load_switch, True)\n", + "system_dp.connect_component(\n", + " load_switch, [dpsimpy.dp.SimNode.gnd, system_dp.node(\"N11\")]\n", + ")\n", + "logger_dp.log_attribute(\"switchedload_i\", \"i_intf\", load_switch)\n", + "load_step_event = dpsimpy.event.SwitchEvent(2 - time_step, load_switch, True)\n", "\n", "\n", "sim_dp = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", @@ -227,9 +305,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'DP_CIGRE_MV_withDG_withLoadStep_Powerflow'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"DP_CIGRE_MV_withDG_withLoadStep_Powerflow\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -247,9 +325,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -268,9 +346,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'DP_CIGRE_MV_withDG_withLoadStep'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"DP_CIGRE_MV_withDG_withLoadStep\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -288,9 +366,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V' and ts_name[-2:] == '.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\" and ts_name[-2:] == \".V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -309,9 +387,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.V':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".V\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -327,12 +411,12 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V' and ts_name[-2:] == '.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\" and ts_name[-2:] == \".V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", - "#plt.ylim([19000,21000])\n", - "plt.xlim([1.9,3])\n", + "# plt.ylim([19000,21000])\n", + "plt.xlim([1.9, 3])\n", "plt.legend()\n", "plt.show()" ] @@ -350,16 +434,20 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,12))\n", + "plt.figure(figsize=(12, 12))\n", "subplot_number = 1\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.V' and ts_name[:-2] != 'N0.V':\n", - " plt.subplot(4,3,subplot_number)\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".V\" and ts_name[:-2] != \"N0.V\":\n", + " plt.subplot(4, 3, subplot_number)\n", " subplot_number += 1\n", - " plt.plot(ts_dpsim[ts_name].interpolate(50e-6).time, ts_dpsim[ts_name].interpolate(50e-6).frequency_shift(50).values, label=ts_name)\n", - " plt.legend(loc='upper right')\n", - " plt.xlim([1.8,3])\n", - " plt.ylim([18500,20000])\n", + " plt.plot(\n", + " ts_dpsim[ts_name].interpolate(50e-6).time,\n", + " ts_dpsim[ts_name].interpolate(50e-6).frequency_shift(50).values,\n", + " label=ts_name,\n", + " )\n", + " plt.legend(loc=\"upper right\")\n", + " plt.xlim([1.8, 3])\n", + " plt.ylim([18500, 20000])\n", "plt.show()" ] }, @@ -376,12 +464,12 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[:4]=='LOAD': \n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[:4] == \"LOAD\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", - "#plt.xlim([0,0.1])\n", - "plt.legend(loc='upper right')\n", + "# plt.xlim([0,0.1])\n", + "plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -398,15 +486,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", + "plt.figure(figsize=(12, 6))\n", "subplot_number = 1\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.I' and ts_name[:4] != 'LOAD':\n", - " plt.subplot(4,3,subplot_number)\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".I\" and ts_name[:4] != \"LOAD\":\n", + " plt.subplot(4, 3, subplot_number)\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", " subplot_number += 1\n", - " plt.legend(loc='upper right')\n", - "#plt.xlim([0,0.1])\n", + " plt.legend(loc=\"upper right\")\n", + "# plt.xlim([0,0.1])\n", "plt.show()" ] }, @@ -430,9 +518,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-7:]=='state_p' or ts_name[-7:]=='state_q':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-7:] == \"state_p\" or ts_name[-7:] == \"state_q\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -451,9 +539,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-7:]!='state_p' and ts_name[-7:]!='state_q' and 'state' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-7:] != \"state_p\" and ts_name[-7:] != \"state_q\" and \"state\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -472,9 +560,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'state' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"state\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -490,9 +584,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'state' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"state\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -508,9 +608,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -529,9 +629,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -547,9 +653,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -565,9 +677,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -586,9 +698,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -604,9 +722,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -622,9 +746,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -643,12 +767,14 @@ "metadata": {}, "outputs": [], "source": [ - "pv_N11_s_intf = ts_dpsim['pv_N11_v_intf'].values*np.conj(ts_dpsim['pv_N11_i_intf'].values)\n", - "plt.figure(figsize=(12,6))\n", - "plt.plot(ts_dpsim['pv_N11_v_intf'].time, np.real(pv_N11_s_intf), label='pv_N11_P_intf')\n", - "plt.plot(ts_dpsim['pv_N11_v_intf'].time, np.imag(pv_N11_s_intf), label='pv_N11_Q_intf')\n", + "pv_N11_s_intf = ts_dpsim[\"pv_N11_v_intf\"].values * np.conj(\n", + " ts_dpsim[\"pv_N11_i_intf\"].values\n", + ")\n", + "plt.figure(figsize=(12, 6))\n", + "plt.plot(ts_dpsim[\"pv_N11_v_intf\"].time, np.real(pv_N11_s_intf), label=\"pv_N11_P_intf\")\n", + "plt.plot(ts_dpsim[\"pv_N11_v_intf\"].time, np.imag(pv_N11_s_intf), label=\"pv_N11_Q_intf\")\n", "plt.legend()\n", - "plt.show()\n" + "plt.show()" ] }, { @@ -664,10 +790,22 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))\n", - "print('pv_N11_s_intf' + ': ' + str(np.real(pv_N11_s_intf[0])) + ', ' + str(np.imag(pv_N11_s_intf[0])))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )\n", + "print(\n", + " \"pv_N11_s_intf\"\n", + " + \": \"\n", + " + str(np.real(pv_N11_s_intf[0]))\n", + " + \", \"\n", + " + str(np.imag(pv_N11_s_intf[0]))\n", + ")" ] }, { @@ -683,10 +821,22 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))\n", - "print('pv_N11_s_intf' + ': ' + str(np.real(pv_N11_s_intf[-1])) + ', ' + str(np.imag(pv_N11_s_intf[-1])))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )\n", + "print(\n", + " \"pv_N11_s_intf\"\n", + " + \": \"\n", + " + str(np.real(pv_N11_s_intf[-1]))\n", + " + \", \"\n", + " + str(np.imag(pv_N11_s_intf[-1]))\n", + ")" ] }, { diff --git a/examples/Notebooks/Grids/DP_CIGRE_MV_withoutDG.ipynb b/examples/Notebooks/Grids/DP_CIGRE_MV_withoutDG.ipynb index afc9f6cb9c..0d6a2af4ae 100644 --- a/examples/Notebooks/Grids/DP_CIGRE_MV_withoutDG.ipynb +++ b/examples/Notebooks/Grids/DP_CIGRE_MV_withoutDG.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -67,7 +69,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'DP_CIGRE_MV_withoutDG'\n", + "sim_name = \"DP_CIGRE_MV_withoutDG\"\n", "sim_name_pf = sim_name + \"_Powerflow\"" ] }, @@ -84,13 +86,15 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system_pf = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_pf = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", - " logger_pf.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_pf.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -102,7 +106,7 @@ "sim_pf.do_init_from_nodes_and_terminals(True)\n", "\n", "sim_pf.add_logger(logger_pf)\n", - "sim_pf.run()\n" + "sim_pf.run()" ] }, { @@ -118,22 +122,24 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader2 = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.debug)\n", - "system_dp = reader2.loadCIM(50, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_dp = reader2.loadCIM(\n", + " 50, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "system_dp.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", "\n", "# log node voltages\n", - "logger_dp= dpsimpy.Logger(sim_name)\n", + "logger_dp = dpsimpy.Logger(sim_name)\n", "for node in system_dp.nodes:\n", - " logger_dp.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_dp.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "# log line and load currents\n", "for comp in system_dp.components:\n", " if isinstance(comp, dpsimpy.dp.ph1.PiLine):\n", - " logger_dp.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_dp.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", " if isinstance(comp, dpsimpy.dp.ph1.RXLoad):\n", - " logger_dp.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_dp.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", "\n", "sim_dp = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", "sim_dp.set_system(system_dp)\n", @@ -168,9 +174,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'DP_CIGRE_MV_withoutDG_Powerflow'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"DP_CIGRE_MV_withoutDG_Powerflow\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim_powerflow = read_timeseries_csv(dpsim_result_file)" ] @@ -188,9 +194,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -209,8 +215,14 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -233,9 +245,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'DP_CIGRE_MV_withoutDG'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"DP_CIGRE_MV_withoutDG\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -260,11 +272,11 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V' and ts_name[-2:] == '.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\" and ts_name[-2:] == \".V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", - "plt.legend(loc='upper right')\n", + "plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -281,9 +293,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.V':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".V\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -299,9 +317,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.V':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1:]) + ', ' + str(ts_obj.phase().values[-1:]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".V\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1:])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1:])\n", + " )" ] }, { @@ -317,12 +341,12 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.I' and ts_name[:4] == 'LOAD':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".I\" and ts_name[:4] == \"LOAD\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", - "plt.xlim([0,0.01])\n", - "plt.legend(loc='upper right')\n", + "plt.xlim([0, 0.01])\n", + "plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -339,9 +363,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.I' and ts_name[:4] == 'LOAD':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".I\" and ts_name[:4] == \"LOAD\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -357,9 +387,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-2:] == '.I' and ts_name[:4] == 'LOAD':\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1:]) + ', ' + str(ts_obj.phase().values[-1:]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-2:] == \".I\" and ts_name[:4] == \"LOAD\":\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1:])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1:])\n", + " )" ] }, { @@ -375,8 +411,12 @@ "metadata": {}, "outputs": [], "source": [ - "load_I_3_s = ts_dpsim['N3.V'].values*np.conj(ts_dpsim['LOAD-I-3.I'].values) # ref from CIM: P=225250, Q=139597\n", - "load_H_11_s = ts_dpsim['N11.V'].values*np.conj(ts_dpsim['LOAD-H-11.I'].values) # ref from CIM: P=329800, Q=82656" + "load_I_3_s = ts_dpsim[\"N3.V\"].values * np.conj(\n", + " ts_dpsim[\"LOAD-I-3.I\"].values\n", + ") # ref from CIM: P=225250, Q=139597\n", + "load_H_11_s = ts_dpsim[\"N11.V\"].values * np.conj(\n", + " ts_dpsim[\"LOAD-H-11.I\"].values\n", + ") # ref from CIM: P=329800, Q=82656" ] }, { @@ -392,8 +432,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Load-I-3.S' + ': ' + str(load_I_3_s[0]))\n", - "print('Load-H-11.S' + ': ' + str(load_H_11_s[0]))" + "print(\"Load-I-3.S\" + \": \" + str(load_I_3_s[0]))\n", + "print(\"Load-H-11.S\" + \": \" + str(load_H_11_s[0]))" ] }, { @@ -409,8 +449,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Load-I-3.S' + ': ' + str(load_I_3_s[-1]))\n", - "print('Load-H-11.S' + ': ' + str(load_H_11_s[-1]))" + "print(\"Load-I-3.S\" + \": \" + str(load_I_3_s[-1]))\n", + "print(\"Load-H-11.S\" + \": \" + str(load_H_11_s[-1]))" ] } ], diff --git a/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab.ipynb b/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab.ipynb index 204e721545..e679c42d78 100644 --- a/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab.ipynb +++ b/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX_Dyn/WSCC-09_RX'\n", - "filename = 'WSCC-09'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX_Dyn/WSCC-09_RX\"\n", + "filename = \"WSCC-09\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -51,7 +53,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'WSCC-9bus_dyn'" + "sim_name = \"WSCC-9bus_dyn\"" ] }, { @@ -67,17 +69,23 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system = reader.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.TransientStability)\n", + "system = reader.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.TransientStability,\n", + ")\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", "\n", "for i in range(1, 10):\n", - " logger.log_attribute('v' + str(i), 'v', system.node('BUS' + str(i)))\n", + " logger.log_attribute(\"v\" + str(i), \"v\", system.node(\"BUS\" + str(i)))\n", "\n", "for i in range(1, 4):\n", - " logger.log_attribute('wr_' + str(i), 'w_r', system.component('GEN' + str(i)))\n", + " logger.log_attribute(\"wr_\" + str(i), \"w_r\", system.component(\"GEN\" + str(i)))\n", "\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.info)\n", "sim.set_system(system)\n", @@ -87,7 +95,7 @@ "sim.do_steady_state_init(True)\n", "\n", "sim.add_logger(logger)\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -103,9 +111,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC-9bus_dyn/'\n", - "logName = 'WSCC-9bus_dyn_InitLeftVector'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC-9bus_dyn/\"\n", + "logName = \"WSCC-9bus_dyn_InitLeftVector\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_dpsim_init = rt.read_timeseries_dpsim(logFilename)" @@ -127,7 +135,13 @@ "phasors_init = ts.phasors(ts_dpsim_init)\n", "\n", "for node, phasor in phasors_init.items():\n", - " print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -144,7 +158,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_init.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -161,7 +181,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_init.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1] - phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[-1] - phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1] - phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1] - phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -177,9 +203,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC-9bus_dyn/'\n", - "logName = 'WSCC-9bus_dyn'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC-9bus_dyn/\"\n", + "logName = \"WSCC-9bus_dyn\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_dpsim = rt.read_timeseries_dpsim(logFilename)\n", @@ -199,11 +225,25 @@ "metadata": {}, "outputs": [], "source": [ - "nominal_voltages = {'v1': 16500, 'v2': 18000, 'v3': 13800, \n", - " 'v4': 230000, 'v5': 230000, 'v6': 230000, \n", - " 'v7': 230000, 'v8': 230000, 'v9': 230000} \n", + "nominal_voltages = {\n", + " \"v1\": 16500,\n", + " \"v2\": 18000,\n", + " \"v3\": 13800,\n", + " \"v4\": 230000,\n", + " \"v5\": 230000,\n", + " \"v6\": 230000,\n", + " \"v7\": 230000,\n", + " \"v8\": 230000,\n", + " \"v9\": 230000,\n", + "}\n", "for node, nom_voltage in nominal_voltages.items():\n", - " print(node + ': ' + str(phasors[node]['abs'].values[0] / nom_voltage) + '<' + str(phasors[node]['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasors[node][\"abs\"].values[0] / nom_voltage)\n", + " + \"<\"\n", + " + str(phasors[node][\"phase\"].values[0])\n", + " )" ] }, { @@ -219,8 +259,8 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, phasors['v9']['phase'])\n", - "#plt.xlim(0,0.2)" + "pt.plot_timeseries(1, phasors[\"v9\"][\"phase\"])\n", + "# plt.xlim(0,0.2)" ] }, { @@ -237,7 +277,13 @@ "outputs": [], "source": [ "for node, phasor in phasors.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -246,18 +292,18 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, phasors['v1']['abs'])\n", - "pt.plot_timeseries(1, phasors['v2']['abs'])\n", - "pt.plot_timeseries(1, phasors['v3']['abs'])\n", + "pt.plot_timeseries(1, phasors[\"v1\"][\"abs\"])\n", + "pt.plot_timeseries(1, phasors[\"v2\"][\"abs\"])\n", + "pt.plot_timeseries(1, phasors[\"v3\"][\"abs\"])\n", "\n", - "pt.plot_timeseries(2, phasors['v4']['abs'])\n", - "pt.plot_timeseries(2, phasors['v5']['abs'])\n", - "pt.plot_timeseries(2, phasors['v6']['abs'])\n", - "pt.plot_timeseries(2, phasors['v7']['abs'])\n", - "pt.plot_timeseries(2, phasors['v8']['abs'])\n", - "pt.plot_timeseries(2, phasors['v9']['abs'])\n", - "plt.ylim([200000,240000])\n", - "plt.xlim([0,0.1])" + "pt.plot_timeseries(2, phasors[\"v4\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v5\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v6\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v7\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v8\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v9\"][\"abs\"])\n", + "plt.ylim([200000, 240000])\n", + "plt.xlim([0, 0.1])" ] }, { @@ -267,11 +313,11 @@ "outputs": [], "source": [ "for node, phasor in phasors.items():\n", - " abs_diff = phasor['abs'].values[-1] - phasor['abs'].values[0]\n", + " abs_diff = phasor[\"abs\"].values[-1] - phasor[\"abs\"].values[0]\n", " assert abs_diff < 27\n", - " phase_diff = phasor['phase'].values[-1] - phasor['phase'].values[0]\n", + " phase_diff = phasor[\"phase\"].values[-1] - phasor[\"phase\"].values[0]\n", " assert phase_diff < 0.001\n", - " print(node + ': ' + str(abs_diff) + '<' + str(phase_diff))" + " print(node + \": \" + str(abs_diff) + \"<\" + str(phase_diff))" ] }, { @@ -280,13 +326,13 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, ts_dpsim['wr_1'])\n", - "pt.plot_timeseries(1, ts_dpsim['wr_2'])\n", - "pt.plot_timeseries(1, ts_dpsim['wr_3'])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('mechanical speed (rad/s)')\n", - "#plt.ylim([370,380])\n", - "#plt.xlim([0,0.06])" + "pt.plot_timeseries(1, ts_dpsim[\"wr_1\"])\n", + "pt.plot_timeseries(1, ts_dpsim[\"wr_2\"])\n", + "pt.plot_timeseries(1, ts_dpsim[\"wr_3\"])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"mechanical speed (rad/s)\")\n", + "# plt.ylim([370,380])\n", + "# plt.xlim([0,0.06])" ] } ], diff --git a/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab_Switch.ipynb b/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab_Switch.ipynb index 9fc74088e8..6fd9b4c88f 100644 --- a/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab_Switch.ipynb +++ b/examples/Notebooks/Grids/DP_WSCC9bus_SGTrStab_Switch.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX_Dyn/WSCC-09_RX'\n", - "filename = 'WSCC-09'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX_Dyn/WSCC-09_RX\"\n", + "filename = \"WSCC-09\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -51,7 +53,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'WSCC-9bus_dyn_switch'" + "sim_name = \"WSCC-9bus_dyn_switch\"" ] }, { @@ -67,32 +69,40 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system = reader.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.TransientStability)\n", + "system = reader.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.TransientStability,\n", + ")\n", "\n", "# Extend topology with switch\n", - "sw = dpsimpy.dp.ph1.Switch('Fault', dpsimpy.LogLevel.info)\n", + "sw = dpsimpy.dp.ph1.Switch(\"Fault\", dpsimpy.LogLevel.info)\n", "sw.set_parameters(1e9, 0.1)\n", - "sw.connect([dpsimpy.dp.SimNode.gnd, system.node('BUS6')])\n", + "sw.connect([dpsimpy.dp.SimNode.gnd, system.node(\"BUS6\")])\n", "sw.open()\n", "system.add(sw)\n", "\n", "# Use omegNom for torque conversion in SG models for validation with PSAT\n", - "system.component('GEN1').set_model_flags(False)\n", - "system.component('GEN2').set_model_flags(False)\n", - "system.component('GEN3').set_model_flags(False)\n", + "system.component(\"GEN1\").set_model_flags(False)\n", + "system.component(\"GEN2\").set_model_flags(False)\n", + "system.component(\"GEN3\").set_model_flags(False)\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", "\n", "for i in range(1, 10):\n", - " logger.log_attribute('v' + str(i), 'v', system.node('BUS' + str(i)))\n", + " logger.log_attribute(\"v\" + str(i), \"v\", system.node(\"BUS\" + str(i)))\n", "\n", "for i in range(1, 4):\n", - " logger.log_attribute('wr_' + str(i), 'w_r', system.component('GEN' + str(i)))\n", - " logger.log_attribute('delta_r_' + str(i), 'delta_r', system.component('GEN' + str(i)))\n", - " logger.log_attribute('P_elec_' + str(i), 'P_elec', system.component('GEN' + str(i)))\n", - " logger.log_attribute('P_mech_' + str(i), 'P_mech', system.component('GEN' + str(i)))\n", + " logger.log_attribute(\"wr_\" + str(i), \"w_r\", system.component(\"GEN\" + str(i)))\n", + " logger.log_attribute(\n", + " \"delta_r_\" + str(i), \"delta_r\", system.component(\"GEN\" + str(i))\n", + " )\n", + " logger.log_attribute(\"P_elec_\" + str(i), \"P_elec\", system.component(\"GEN\" + str(i)))\n", + " logger.log_attribute(\"P_mech_\" + str(i), \"P_mech\", system.component(\"GEN\" + str(i)))\n", "\n", "\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", @@ -107,7 +117,7 @@ "sim.add_event(sw_event_1)\n", "\n", "sim.add_logger(logger)\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -123,9 +133,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC-9bus_dyn_switch/'\n", - "logName = 'WSCC-9bus_dyn_switch'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC-9bus_dyn_switch/\"\n", + "logName = \"WSCC-9bus_dyn_switch\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_dpsim = rt.read_timeseries_dpsim(logFilename)\n", @@ -145,11 +155,25 @@ "metadata": {}, "outputs": [], "source": [ - "nominal_voltages = {'v1': 16500, 'v2': 18000, 'v3': 13800, \n", - " 'v4': 230000, 'v5': 230000, 'v6': 230000, \n", - " 'v7': 230000, 'v8': 230000, 'v9': 230000} \n", + "nominal_voltages = {\n", + " \"v1\": 16500,\n", + " \"v2\": 18000,\n", + " \"v3\": 13800,\n", + " \"v4\": 230000,\n", + " \"v5\": 230000,\n", + " \"v6\": 230000,\n", + " \"v7\": 230000,\n", + " \"v8\": 230000,\n", + " \"v9\": 230000,\n", + "}\n", "for node, nom_voltage in nominal_voltages.items():\n", - " print(node + ': ' + str(phasors[node]['abs'].values[0] / nom_voltage) + '<' + str(phasors[node]['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasors[node][\"abs\"].values[0] / nom_voltage)\n", + " + \"<\"\n", + " + str(phasors[node][\"phase\"].values[0])\n", + " )" ] }, { @@ -166,21 +190,21 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(phasors['v1']['abs'].time, phasors['v1']['abs'].values, label='v1.abs')\n", - "plt.plot(phasors['v2']['abs'].time, phasors['v2']['abs'].values, label='v2.abs')\n", - "plt.plot(phasors['v3']['abs'].time, phasors['v3']['abs'].values, label='v3.abs')\n", + "plt.plot(phasors[\"v1\"][\"abs\"].time, phasors[\"v1\"][\"abs\"].values, label=\"v1.abs\")\n", + "plt.plot(phasors[\"v2\"][\"abs\"].time, phasors[\"v2\"][\"abs\"].values, label=\"v2.abs\")\n", + "plt.plot(phasors[\"v3\"][\"abs\"].time, phasors[\"v3\"][\"abs\"].values, label=\"v3.abs\")\n", "plt.legend()\n", - "plt.ylim([0,20000])\n", + "plt.ylim([0, 20000])\n", "\n", "plt.figure()\n", - "plt.plot(phasors['v4']['abs'].time, phasors['v4']['abs'].values, label='v4.abs')\n", - "plt.plot(phasors['v5']['abs'].time, phasors['v5']['abs'].values, label='v5.abs')\n", - "plt.plot(phasors['v6']['abs'].time, phasors['v6']['abs'].values, label='v6.abs')\n", - "plt.plot(phasors['v7']['abs'].time, phasors['v7']['abs'].values, label='v7.abs')\n", - "plt.plot(phasors['v8']['abs'].time, phasors['v8']['abs'].values, label='v8.abs')\n", - "plt.plot(phasors['v9']['abs'].time, phasors['v9']['abs'].values, label='v9.abs')\n", + "plt.plot(phasors[\"v4\"][\"abs\"].time, phasors[\"v4\"][\"abs\"].values, label=\"v4.abs\")\n", + "plt.plot(phasors[\"v5\"][\"abs\"].time, phasors[\"v5\"][\"abs\"].values, label=\"v5.abs\")\n", + "plt.plot(phasors[\"v6\"][\"abs\"].time, phasors[\"v6\"][\"abs\"].values, label=\"v6.abs\")\n", + "plt.plot(phasors[\"v7\"][\"abs\"].time, phasors[\"v7\"][\"abs\"].values, label=\"v7.abs\")\n", + "plt.plot(phasors[\"v8\"][\"abs\"].time, phasors[\"v8\"][\"abs\"].values, label=\"v8.abs\")\n", + "plt.plot(phasors[\"v9\"][\"abs\"].time, phasors[\"v9\"][\"abs\"].values, label=\"v9.abs\")\n", "plt.legend()\n", - "plt.ylim([0,240000])" + "plt.ylim([0, 240000])" ] }, { @@ -197,12 +221,12 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_dpsim['wr_1'].time, ts_dpsim['wr_1'].values)\n", - "plt.plot(ts_dpsim['wr_2'].time, ts_dpsim['wr_2'].values)\n", - "plt.plot(ts_dpsim['wr_3'].time, ts_dpsim['wr_3'].values)\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('mechanical speed (rad/s)')\n", - "#plt.savefig('wscc_9bus_fault_gen_speed.pdf')" + "plt.plot(ts_dpsim[\"wr_1\"].time, ts_dpsim[\"wr_1\"].values)\n", + "plt.plot(ts_dpsim[\"wr_2\"].time, ts_dpsim[\"wr_2\"].values)\n", + "plt.plot(ts_dpsim[\"wr_3\"].time, ts_dpsim[\"wr_3\"].values)\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"mechanical speed (rad/s)\")\n", + "# plt.savefig('wscc_9bus_fault_gen_speed.pdf')" ] }, { @@ -222,12 +246,12 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://git.rwth-aachen.de/acs/public/simulation/dpsim/dpsim-results/raw/master/WSCC-9bus/WSCC-9bus_dyn_switch_mod_inertia.csv'\n", - "local_file = 'reference-results/WSCC-9bus_dyn_switch.csv'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://git.rwth-aachen.de/acs/public/simulation/dpsim/dpsim-results/raw/master/WSCC-9bus/WSCC-9bus_dyn_switch_mod_inertia.csv\"\n", + "local_file = \"reference-results/WSCC-9bus_dyn_switch.csv\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", "ts_sl = rt.read_timeseries_simulink(local_file)\n", "phasors_sl = ts.phasors(ts_sl)" @@ -240,21 +264,21 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(phasors_sl['v1']['abs'].time, phasors_sl['v1']['abs'].values, label='v1.abs')\n", - "plt.plot(phasors_sl['v2']['abs'].time, phasors_sl['v2']['abs'].values, label='v2.abs')\n", - "plt.plot(phasors_sl['v3']['abs'].time, phasors_sl['v3']['abs'].values, label='v3.abs')\n", + "plt.plot(phasors_sl[\"v1\"][\"abs\"].time, phasors_sl[\"v1\"][\"abs\"].values, label=\"v1.abs\")\n", + "plt.plot(phasors_sl[\"v2\"][\"abs\"].time, phasors_sl[\"v2\"][\"abs\"].values, label=\"v2.abs\")\n", + "plt.plot(phasors_sl[\"v3\"][\"abs\"].time, phasors_sl[\"v3\"][\"abs\"].values, label=\"v3.abs\")\n", "plt.legend()\n", - "plt.ylim([0,20000])\n", + "plt.ylim([0, 20000])\n", "\n", "plt.figure()\n", - "plt.plot(phasors_sl['v4']['abs'].time, phasors_sl['v4']['abs'].values, label='v4.abs')\n", - "plt.plot(phasors_sl['v5']['abs'].time, phasors_sl['v5']['abs'].values, label='v5.abs')\n", - "plt.plot(phasors_sl['v6']['abs'].time, phasors_sl['v6']['abs'].values, label='v6.abs')\n", - "plt.plot(phasors_sl['v7']['abs'].time, phasors_sl['v7']['abs'].values, label='v7.abs')\n", - "plt.plot(phasors_sl['v8']['abs'].time, phasors_sl['v8']['abs'].values, label='v8.abs')\n", - "plt.plot(phasors_sl['v9']['abs'].time, phasors_sl['v9']['abs'].values, label='v9.abs')\n", + "plt.plot(phasors_sl[\"v4\"][\"abs\"].time, phasors_sl[\"v4\"][\"abs\"].values, label=\"v4.abs\")\n", + "plt.plot(phasors_sl[\"v5\"][\"abs\"].time, phasors_sl[\"v5\"][\"abs\"].values, label=\"v5.abs\")\n", + "plt.plot(phasors_sl[\"v6\"][\"abs\"].time, phasors_sl[\"v6\"][\"abs\"].values, label=\"v6.abs\")\n", + "plt.plot(phasors_sl[\"v7\"][\"abs\"].time, phasors_sl[\"v7\"][\"abs\"].values, label=\"v7.abs\")\n", + "plt.plot(phasors_sl[\"v8\"][\"abs\"].time, phasors_sl[\"v8\"][\"abs\"].values, label=\"v8.abs\")\n", + "plt.plot(phasors_sl[\"v9\"][\"abs\"].time, phasors_sl[\"v9\"][\"abs\"].values, label=\"v9.abs\")\n", "plt.legend()\n", - "plt.ylim([0,240000])" + "plt.ylim([0, 240000])" ] }, { @@ -264,11 +288,11 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_sl['wr_1'].time, ts_sl['wr_1'].values)\n", - "plt.plot(ts_sl['wr_2'].time, ts_sl['wr_2'].values)\n", - "plt.plot(ts_sl['wr_3'].time, ts_sl['wr_3'].values)\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('mechanical speed (rad/s)')" + "plt.plot(ts_sl[\"wr_1\"].time, ts_sl[\"wr_1\"].values)\n", + "plt.plot(ts_sl[\"wr_2\"].time, ts_sl[\"wr_2\"].values)\n", + "plt.plot(ts_sl[\"wr_3\"].time, ts_sl[\"wr_3\"].values)\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"mechanical speed (rad/s)\")" ] }, { @@ -278,6 +302,7 @@ "outputs": [], "source": [ "import numpy as np\n", + "\n", "# assert np.all(ts_sl['wr_1'].values - ts_dpsim['wr_1'].values < 0.01)" ] } diff --git a/examples/Notebooks/Grids/DP_WSCC9bus_SGVoltageSource.ipynb b/examples/Notebooks/Grids/DP_WSCC9bus_SGVoltageSource.ipynb index 6747701970..5310a7165f 100644 --- a/examples/Notebooks/Grids/DP_WSCC9bus_SGVoltageSource.ipynb +++ b/examples/Notebooks/Grids/DP_WSCC9bus_SGVoltageSource.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX/WSCC-09_RX'\n", - "filename = 'WSCC-09_RX_WithoutSyngenParams'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX/WSCC-09_RX\"\n", + "filename = \"WSCC-09_RX_WithoutSyngenParams\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -51,7 +53,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'WSCC-9bus'" + "sim_name = \"WSCC-9bus\"" ] }, { @@ -74,14 +76,20 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system = reader.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.IdealVoltageSource)\n", + "system = reader.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.IdealVoltageSource,\n", + ")\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", "\n", "for i in range(1, 10):\n", - " logger.log_attribute('v' + str(i), 'v', system.node('BUS' + str(i)))\n", + " logger.log_attribute(\"v\" + str(i), \"v\", system.node(\"BUS\" + str(i)))\n", "\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.info)\n", "sim.set_system(system)\n", @@ -91,7 +99,7 @@ "sim.do_steady_state_init(True)\n", "\n", "sim.add_logger(logger)\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -100,9 +108,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC-9bus/'\n", - "logName = 'WSCC-9bus_InitLeftVector'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC-9bus/\"\n", + "logName = \"WSCC-9bus_InitLeftVector\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_dpsim_init = rt.read_timeseries_dpsim(logFilename)" @@ -124,7 +132,13 @@ "phasors_init = ts.phasors(ts_dpsim_init)\n", "\n", "for node, phasor in phasors_init.items():\n", - " print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -141,7 +155,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_init.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -158,7 +178,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_init.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1] - phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[-1] - phasor['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1] - phasor[\"abs\"].values[0])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1] - phasor[\"phase\"].values[0])\n", + " )" ] }, { @@ -174,9 +200,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC-9bus/'\n", - "logName = 'WSCC-9bus'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC-9bus/\"\n", + "logName = \"WSCC-9bus\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_dpsim = rt.read_timeseries_dpsim(logFilename)\n", @@ -196,11 +222,25 @@ "metadata": {}, "outputs": [], "source": [ - "nominal_voltages = {'v1': 16500, 'v2': 18000, 'v3': 13800, \n", - " 'v4': 230000, 'v5': 230000, 'v6': 230000, \n", - " 'v7': 230000, 'v8': 230000, 'v9': 230000} \n", + "nominal_voltages = {\n", + " \"v1\": 16500,\n", + " \"v2\": 18000,\n", + " \"v3\": 13800,\n", + " \"v4\": 230000,\n", + " \"v5\": 230000,\n", + " \"v6\": 230000,\n", + " \"v7\": 230000,\n", + " \"v8\": 230000,\n", + " \"v9\": 230000,\n", + "}\n", "for node, nom_voltage in nominal_voltages.items():\n", - " print(node + ': ' + str(phasors[node]['abs'].values[0] / nom_voltage) + '<' + str(phasors[node]['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasors[node][\"abs\"].values[0] / nom_voltage)\n", + " + \"<\"\n", + " + str(phasors[node][\"phase\"].values[0])\n", + " )" ] }, { @@ -218,7 +258,7 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, phasors['v9']['phase'])\n", + "pt.plot_timeseries(1, phasors[\"v9\"][\"phase\"])\n", "plt.ylim([2.10405, 2.1042])" ] }, @@ -235,7 +275,7 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, phasors_init['n00007f00']['phase'])\n", + "pt.plot_timeseries(1, phasors_init[\"n00007f00\"][\"phase\"])\n", "plt.ylim([2.10405, 2.1042])" ] }, @@ -253,7 +293,13 @@ "outputs": [], "source": [ "for node, phasor in phasors.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -262,17 +308,17 @@ "metadata": {}, "outputs": [], "source": [ - "pt.plot_timeseries(1, phasors['v1']['abs'])\n", - "pt.plot_timeseries(1, phasors['v2']['abs'])\n", - "pt.plot_timeseries(1, phasors['v3']['abs'])\n", + "pt.plot_timeseries(1, phasors[\"v1\"][\"abs\"])\n", + "pt.plot_timeseries(1, phasors[\"v2\"][\"abs\"])\n", + "pt.plot_timeseries(1, phasors[\"v3\"][\"abs\"])\n", "\n", - "pt.plot_timeseries(2, phasors['v4']['abs'])\n", - "pt.plot_timeseries(2, phasors['v5']['abs'])\n", - "pt.plot_timeseries(2, phasors['v6']['abs'])\n", - "pt.plot_timeseries(2, phasors['v7']['abs'])\n", - "pt.plot_timeseries(2, phasors['v8']['abs'])\n", - "pt.plot_timeseries(2, phasors['v9']['abs'])\n", - "plt.gca().axes.set_ylim([200000,240000])" + "pt.plot_timeseries(2, phasors[\"v4\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v5\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v6\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v7\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v8\"][\"abs\"])\n", + "pt.plot_timeseries(2, phasors[\"v9\"][\"abs\"])\n", + "plt.gca().axes.set_ylim([200000, 240000])" ] }, { @@ -289,11 +335,11 @@ "outputs": [], "source": [ "for node, phasor in phasors.items():\n", - " abs_diff = phasor['abs'].values[-1] - phasor['abs'].values[0]\n", + " abs_diff = phasor[\"abs\"].values[-1] - phasor[\"abs\"].values[0]\n", " assert abs_diff < 20\n", - " phase_diff = phasor['phase'].values[-1] - phasor['phase'].values[0]\n", + " phase_diff = phasor[\"phase\"].values[-1] - phasor[\"phase\"].values[0]\n", " assert phase_diff < 0.001\n", - " print(node + ': ' + str(abs_diff) + '<' + str(phase_diff))" + " print(node + \": \" + str(abs_diff) + \"<\" + str(phase_diff))" ] } ], diff --git a/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG.ipynb b/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG.ipynb index b80d326ebe..404f27a6c1 100644 --- a/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG.ipynb +++ b/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG.ipynb @@ -25,18 +25,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -68,7 +70,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'EMT_CIGRE_MV_withDG'\n", + "sim_name = \"EMT_CIGRE_MV_withDG\"\n", "sim_name_pf = sim_name + \"_Powerflow\"" ] }, @@ -86,30 +88,64 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system_pf = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_pf = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_pf.node('N' + str(n))\n", - " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_pf.node(\"N\" + str(n))\n", + " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_pf.add(pv)\n", " system_pf.connect_component(pv, [connection_node])\n", "\n", "\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", - " logger_pf.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_pf.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -121,7 +157,7 @@ "sim_pf.do_init_from_nodes_and_terminals(True)\n", "\n", "sim_pf.add_logger(logger_pf)\n", - "sim_pf.run()\n" + "sim_pf.run()" ] }, { @@ -138,67 +174,108 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader2 = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.debug)\n", - "system_emt = reader2.loadCIM(50, files, dpsimpy.Domain.EMT, dpsimpy.PhaseType.ABC, dpsimpy.GeneratorType.NONE)\n", + "system_emt = reader2.loadCIM(\n", + " 50, files, dpsimpy.Domain.EMT, dpsimpy.PhaseType.ABC, dpsimpy.GeneratorType.NONE\n", + ")\n", "\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_emt.node('N' + str(n))\n", - " pv = dpsimpy.emt.ph3.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power=5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3, omega = 2 * np.pi * 50)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_emt.node(\"N\" + str(n))\n", + " pv = dpsimpy.emt.ph3.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " omega=2 * np.pi * 50,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_emt.add(pv)\n", " system_emt.connect_component(pv, [connection_node])\n", "\n", "system_emt.init_with_powerflow(system_pf, dpsimpy.Domain.EMT)\n", "\n", "# log node voltages\n", - "logger_emt= dpsimpy.Logger(sim_name)\n", + "logger_emt = dpsimpy.Logger(sim_name)\n", "for node in system_emt.nodes:\n", - " logger_emt.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_emt.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "# log line and load currents\n", "for comp in system_emt.components:\n", " if isinstance(comp, dpsimpy.emt.ph3.PiLine):\n", - " logger_emt.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_emt.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", " if isinstance(comp, dpsimpy.emt.ph3.RXLoad):\n", - " logger_emt.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_emt.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", "\n", "# log output of PV connected at N11\n", - "pv_name = 'pv_N11'\n", + "pv_name = \"pv_N11\"\n", "pv = system_emt.component(pv_name)\n", "input_names = [\n", - " \"pv_powerctrl_input_pref\", \"pv_powerctrl_input_qref\", \"pv_powerctrl_input_vcd\",\n", - " \"pv_powerctrl_input_vcq\", \"pv_powerctrl_input_ircd\", \"pv_powerctrl_input_ircq\"\n", + " \"pv_powerctrl_input_pref\",\n", + " \"pv_powerctrl_input_qref\",\n", + " \"pv_powerctrl_input_vcd\",\n", + " \"pv_powerctrl_input_vcq\",\n", + " \"pv_powerctrl_input_ircd\",\n", + " \"pv_powerctrl_input_ircq\",\n", "]\n", - "logger_emt.log_attribute(input_names, 'powerctrl_inputs', pv)\n", + "logger_emt.log_attribute(input_names, \"powerctrl_inputs\", pv)\n", "\n", "state_names = [\n", - " \"pv_powerctrl_state_p\", \"pv_powerctrl_state_q\", \"pv_powerctrl_state_phid\",\n", - " \"pv_powerctrl_state_phiq\", \"pv_powerctrl_state_gammad\", \"pv_powerctrl_state_gammaq\"\n", + " \"pv_powerctrl_state_p\",\n", + " \"pv_powerctrl_state_q\",\n", + " \"pv_powerctrl_state_phid\",\n", + " \"pv_powerctrl_state_phiq\",\n", + " \"pv_powerctrl_state_gammad\",\n", + " \"pv_powerctrl_state_gammaq\",\n", "]\n", - "logger_emt.log_attribute(state_names, 'powerctrl_states', pv)\n", + "logger_emt.log_attribute(state_names, \"powerctrl_states\", pv)\n", "\n", - "output_names = [\n", - " \"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"\n", - "]\n", + "output_names = [\"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"]\n", "\n", - "logger_emt.log_attribute(output_names, 'powerctrl_outputs', pv)\n", + "logger_emt.log_attribute(output_names, \"powerctrl_outputs\", pv)\n", "\n", - "logger_emt.log_attribute(pv_name + '_v_intf', 'v_intf', pv)\n", - "logger_emt.log_attribute(pv_name + '_i_intf', 'i_intf', pv)\n", - "logger_emt.log_attribute(pv_name + '_pll_output', 'pll_output', pv)\n", - "logger_emt.log_attribute(pv_name + '_vsref', 'Vsref', pv)\n", - "logger_emt.log_attribute(pv_name + '_vs', 'Vs', pv)\n", + "logger_emt.log_attribute(pv_name + \"_v_intf\", \"v_intf\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_i_intf\", \"i_intf\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_pll_output\", \"pll_output\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_vsref\", \"Vsref\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_vs\", \"Vs\", pv)\n", "\n", "sim_emt = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", "sim_emt.set_system(system_emt)\n", @@ -236,11 +313,11 @@ "outputs": [], "source": [ "time_step = 0.001\n", - "num_steps_window = int(0.02/time_step)\n", + "num_steps_window = int(0.02 / time_step)\n", "\n", - "modelName = 'EMT_CIGRE_MV_withDG_Powerflow'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"EMT_CIGRE_MV_withDG_Powerflow\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim_powerflow = read_timeseries_csv(dpsim_result_file)" ] @@ -259,9 +336,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 8))\n", + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -281,8 +358,14 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -307,9 +390,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'EMT_CIGRE_MV_withDG'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"EMT_CIGRE_MV_withDG\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -336,15 +419,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,12))\n", + "plt.figure(figsize=(12, 12))\n", "subplot_number = 1\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-3:] == 'V_0' and ts_name[:-2] != 'N0.V':\n", - " plt.subplot(4,3,subplot_number)\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-3:] == \"V_0\" and ts_name[:-2] != \"N0.V\":\n", + " plt.subplot(4, 3, subplot_number)\n", " subplot_number += 1\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", - " plt.legend(loc='upper right')\n", - " plt.xlim([-0.03,1])\n", + " plt.legend(loc=\"upper right\")\n", + " plt.xlim([-0.03, 1])\n", "plt.show()" ] }, @@ -362,9 +445,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-3:] == 'V_0':\n", - " print(ts_name + ': ' + str(ts_obj.values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-3:] == \"V_0\":\n", + " print(ts_name + \": \" + str(ts_obj.values[0]))" ] }, { @@ -381,9 +464,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-3:] == 'V_0':\n", - " print(ts_name + ': ' + str(max(ts_obj.values[-num_steps_window:])))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-3:] == \"V_0\":\n", + " print(ts_name + \": \" + str(max(ts_obj.values[-num_steps_window:])))" ] }, { @@ -408,9 +491,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-7:]=='state_p' or ts_name[-7:]=='state_q':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-7:] == \"state_p\" or ts_name[-7:] == \"state_q\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -430,9 +513,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-7:]!='state_p' and ts_name[-7:]!='state_q' and 'state' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-7:] != \"state_p\" and ts_name[-7:] != \"state_q\" and \"state\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -452,9 +535,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'state' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"state\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -471,9 +560,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'state' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"state\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -490,9 +585,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -512,9 +607,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -531,9 +632,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'input' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"input\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -550,9 +657,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -572,9 +679,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[0]) + ', ' + str(ts_obj.phase().values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[0])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[0])\n", + " )" ] }, { @@ -591,9 +704,15 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'output' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.abs().values[-1]) + ', ' + str(ts_obj.phase().values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"output\" in ts_name:\n", + " print(\n", + " ts_name\n", + " + \": \"\n", + " + str(ts_obj.abs().values[-1])\n", + " + \", \"\n", + " + str(ts_obj.phase().values[-1])\n", + " )" ] }, { @@ -610,14 +729,14 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "subplot_number = 1 \n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " plt.subplot(2,3,subplot_number)\n", + "plt.figure(figsize=(12, 6))\n", + "subplot_number = 1\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " plt.subplot(2, 3, subplot_number)\n", " subplot_number += 1\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", - " plt.legend(loc='upper right')\n", + " plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -635,11 +754,17 @@ "metadata": {}, "outputs": [], "source": [ - "pv_N11_p_inst_intf = ts_dpsim['pv_N11_v_intf_0'].values*ts_dpsim['pv_N11_i_intf_0'].values+ts_dpsim['pv_N11_v_intf_1'].values*ts_dpsim['pv_N11_i_intf_1'].values+ts_dpsim['pv_N11_v_intf_2'].values*ts_dpsim['pv_N11_i_intf_2'].values\n", - "plt.figure(figsize=(12,6))\n", - "plt.plot(ts_dpsim['pv_N11_v_intf_0'].time, pv_N11_p_inst_intf, label='pv_N11_p_inst_intf')\n", + "pv_N11_p_inst_intf = (\n", + " ts_dpsim[\"pv_N11_v_intf_0\"].values * ts_dpsim[\"pv_N11_i_intf_0\"].values\n", + " + ts_dpsim[\"pv_N11_v_intf_1\"].values * ts_dpsim[\"pv_N11_i_intf_1\"].values\n", + " + ts_dpsim[\"pv_N11_v_intf_2\"].values * ts_dpsim[\"pv_N11_i_intf_2\"].values\n", + ")\n", + "plt.figure(figsize=(12, 6))\n", + "plt.plot(\n", + " ts_dpsim[\"pv_N11_v_intf_0\"].time, pv_N11_p_inst_intf, label=\"pv_N11_p_inst_intf\"\n", + ")\n", "plt.legend()\n", - "plt.show()\n" + "plt.show()" ] }, { @@ -656,10 +781,10 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.values[0]))\n", - "print('pv_N11_p_inst_intf' + ': ' + str(pv_N11_p_inst_intf[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " print(ts_name + \": \" + str(ts_obj.values[0]))\n", + "print(\"pv_N11_p_inst_intf\" + \": \" + str(pv_N11_p_inst_intf[0]))" ] }, { @@ -676,10 +801,10 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if 'intf' in ts_name:\n", - " print(ts_name + ': ' + str(ts_obj.values[-1]))\n", - "print('pv_N11_p_inst_intf' + ': ' + str(pv_N11_p_inst_intf[-1:]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if \"intf\" in ts_name:\n", + " print(ts_name + \": \" + str(ts_obj.values[-1]))\n", + "print(\"pv_N11_p_inst_intf\" + \": \" + str(pv_N11_p_inst_intf[-1:]))" ] } ], diff --git a/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG_withLoadStep.ipynb b/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG_withLoadStep.ipynb index a6d8d10faa..738496a6a9 100644 --- a/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG_withLoadStep.ipynb +++ b/examples/Notebooks/Grids/EMT_CIGRE_MV_withDG_withLoadStep.ipynb @@ -25,18 +25,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -68,7 +70,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'EMT_CIGRE_MV_withDG_withLoadStep'\n", + "sim_name = \"EMT_CIGRE_MV_withDG_withLoadStep\"\n", "sim_name_pf = sim_name + \"_Powerflow\"" ] }, @@ -86,30 +88,64 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system_pf = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_pf = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_pf.node('N' + str(n))\n", - " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_pf.node(\"N\" + str(n))\n", + " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_pf.add(pv)\n", " system_pf.connect_component(pv, [connection_node])\n", "\n", "\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", - " logger_pf.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_pf.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -121,7 +157,7 @@ "sim_pf.do_init_from_nodes_and_terminals(True)\n", "\n", "sim_pf.add_logger(logger_pf)\n", - "sim_pf.run()\n" + "sim_pf.run()" ] }, { @@ -138,78 +174,121 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader2 = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.debug)\n", - "system_emt = reader2.loadCIM(50, files, dpsimpy.Domain.EMT, dpsimpy.PhaseType.ABC, dpsimpy.GeneratorType.NONE)\n", + "system_emt = reader2.loadCIM(\n", + " 50, files, dpsimpy.Domain.EMT, dpsimpy.PhaseType.ABC, dpsimpy.GeneratorType.NONE\n", + ")\n", "\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system_emt.node('N' + str(n))\n", - " pv = dpsimpy.emt.ph3.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power=5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3, omega = 2 * np.pi * 50)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system_emt.node(\"N\" + str(n))\n", + " pv = dpsimpy.emt.ph3.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " omega=2 * np.pi * 50,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system_emt.add(pv)\n", " system_emt.connect_component(pv, [connection_node])\n", "\n", "system_emt.init_with_powerflow(system_pf, dpsimpy.Domain.EMT)\n", "\n", "# log node voltages\n", - "logger_emt= dpsimpy.Logger(sim_name)\n", + "logger_emt = dpsimpy.Logger(sim_name)\n", "for node in system_emt.nodes:\n", - " logger_emt.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_emt.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "# log line and load currents\n", "for comp in system_emt.components:\n", " if isinstance(comp, dpsimpy.emt.ph3.PiLine):\n", - " logger_emt.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_emt.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", " if isinstance(comp, dpsimpy.emt.ph3.RXLoad):\n", - " logger_emt.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_emt.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", "\n", "# log output of PV connected at N11\n", - "pv_name = 'pv_N11'\n", + "pv_name = \"pv_N11\"\n", "pv = system_emt.component(pv_name)\n", "input_names = [\n", - " \"pv_powerctrl_input_pref\", \"pv_powerctrl_input_qref\", \"pv_powerctrl_input_vcd\",\n", - " \"pv_powerctrl_input_vcq\", \"pv_powerctrl_input_ircd\", \"pv_powerctrl_input_ircq\"\n", + " \"pv_powerctrl_input_pref\",\n", + " \"pv_powerctrl_input_qref\",\n", + " \"pv_powerctrl_input_vcd\",\n", + " \"pv_powerctrl_input_vcq\",\n", + " \"pv_powerctrl_input_ircd\",\n", + " \"pv_powerctrl_input_ircq\",\n", "]\n", - "logger_emt.log_attribute(input_names, 'powerctrl_inputs', pv)\n", + "logger_emt.log_attribute(input_names, \"powerctrl_inputs\", pv)\n", "\n", "state_names = [\n", - " \"pv_powerctrl_state_p\", \"pv_powerctrl_state_q\", \"pv_powerctrl_state_phid\",\n", - " \"pv_powerctrl_state_phiq\", \"pv_powerctrl_state_gammad\", \"pv_powerctrl_state_gammaq\"\n", + " \"pv_powerctrl_state_p\",\n", + " \"pv_powerctrl_state_q\",\n", + " \"pv_powerctrl_state_phid\",\n", + " \"pv_powerctrl_state_phiq\",\n", + " \"pv_powerctrl_state_gammad\",\n", + " \"pv_powerctrl_state_gammaq\",\n", "]\n", - "logger_emt.log_attribute(state_names, 'powerctrl_states', pv)\n", + "logger_emt.log_attribute(state_names, \"powerctrl_states\", pv)\n", "\n", - "output_names = [\n", - " \"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"\n", - "]\n", + "output_names = [\"pv_powerctrl_output_vsd\", \"pv_powerctrl_output_vsq\"]\n", "\n", - "logger_emt.log_attribute(output_names, 'powerctrl_outputs', pv)\n", + "logger_emt.log_attribute(output_names, \"powerctrl_outputs\", pv)\n", "\n", - "logger_emt.log_attribute(pv_name + '_v_intf', 'v_intf', pv)\n", - "logger_emt.log_attribute(pv_name + '_i_intf', 'i_intf', pv)\n", - "logger_emt.log_attribute(pv_name + '_pll_output', 'pll_output', pv)\n", - "logger_emt.log_attribute(pv_name + '_vsref', 'Vsref', pv)\n", - "logger_emt.log_attribute(pv_name + '_vs', 'Vs', pv)\n", + "logger_emt.log_attribute(pv_name + \"_v_intf\", \"v_intf\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_i_intf\", \"i_intf\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_pll_output\", \"pll_output\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_vsref\", \"Vsref\", pv)\n", + "logger_emt.log_attribute(pv_name + \"_vs\", \"Vs\", pv)\n", "\n", "# load step sized in absolute terms\n", "load_switch = dpsimpy.emt.ph3.Switch(\"Load_Add_Switch_N11\", dpsimpy.LogLevel.debug)\n", - "connection_node = system_emt.node('N11')\n", - "resistance = np.abs(connection_node.initial_single_voltage())**2 / 1500.0e3\n", + "connection_node = system_emt.node(\"N11\")\n", + "resistance = np.abs(connection_node.initial_single_voltage()) ** 2 / 1500.0e3\n", "load_switch.set_parameters(np.identity(3) * 1e9, np.identity(3) * resistance)\n", "load_switch.open()\n", "system_emt.add(load_switch)\n", - "system_emt.connect_component(load_switch, [dpsimpy.emt.SimNode.gnd, system_emt.node('N11')])\n", - "logger_emt.log_attribute('switchedload_i', 'i_intf', load_switch)\n", - "load_step_event = dpsimpy.event.SwitchEvent3Ph(2 - time_step, load_switch, True)\n", + "system_emt.connect_component(\n", + " load_switch, [dpsimpy.emt.SimNode.gnd, system_emt.node(\"N11\")]\n", + ")\n", + "logger_emt.log_attribute(\"switchedload_i\", \"i_intf\", load_switch)\n", + "load_step_event = dpsimpy.event.SwitchEvent3Ph(2 - time_step, load_switch, True)\n", "\n", "\n", "sim_emt = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", @@ -248,9 +327,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'EMT_CIGRE_MV_withDG_withLoadStep_Powerflow'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"EMT_CIGRE_MV_withDG_withLoadStep_Powerflow\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -269,9 +348,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -291,9 +370,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'EMT_CIGRE_MV_withDG_withLoadStep'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"EMT_CIGRE_MV_withDG_withLoadStep\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -320,9 +399,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-3:] == 'V_0' and ts_name[:-2] != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-3:] == \"V_0\" and ts_name[:-2] != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -342,9 +421,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-3:] == 'I_0':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-3:] == \"I_0\":\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", "plt.legend()\n", "plt.show()" diff --git a/examples/Notebooks/Grids/EMT_CIGRE_MV_withoutDG.ipynb b/examples/Notebooks/Grids/EMT_CIGRE_MV_withoutDG.ipynb index 7dfbf10b54..d26a8b2b1a 100644 --- a/examples/Notebooks/Grids/EMT_CIGRE_MV_withoutDG.ipynb +++ b/examples/Notebooks/Grids/EMT_CIGRE_MV_withoutDG.ipynb @@ -25,18 +25,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -68,7 +70,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'EMT_CIGRE_MV_withoutDG'\n", + "sim_name = \"EMT_CIGRE_MV_withoutDG\"\n", "sim_name_pf = sim_name + \"_Powerflow\"" ] }, @@ -86,13 +88,15 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system_pf = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system_pf = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", - " logger_pf.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_pf.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, dpsimpy.LogLevel.debug)\n", "sim_pf.set_system(system_pf)\n", @@ -104,7 +108,7 @@ "sim_pf.do_init_from_nodes_and_terminals(True)\n", "\n", "sim_pf.add_logger(logger_pf)\n", - "sim_pf.run()\n" + "sim_pf.run()" ] }, { @@ -121,23 +125,25 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader2 = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.debug)\n", - "system_emt = reader2.loadCIM(50, files, dpsimpy.Domain.EMT, dpsimpy.PhaseType.ABC, dpsimpy.GeneratorType.NONE)\n", + "system_emt = reader2.loadCIM(\n", + " 50, files, dpsimpy.Domain.EMT, dpsimpy.PhaseType.ABC, dpsimpy.GeneratorType.NONE\n", + ")\n", "\n", "system_emt.init_with_powerflow(system_pf, dpsimpy.Domain.EMT)\n", "\n", "# log node voltages\n", - "logger_emt= dpsimpy.Logger(sim_name)\n", + "logger_emt = dpsimpy.Logger(sim_name)\n", "for node in system_emt.nodes:\n", - " logger_emt.log_attribute(node.name() + '.V', 'v', node)\n", + " logger_emt.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "# log line and load currents\n", "for comp in system_emt.components:\n", " if isinstance(comp, dpsimpy.emt.ph3.PiLine):\n", - " logger_emt.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_emt.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", " if isinstance(comp, dpsimpy.emt.ph3.RXLoad):\n", - " logger_emt.log_attribute(comp.name() + '.I', 'i_intf', comp)\n", + " logger_emt.log_attribute(comp.name() + \".I\", \"i_intf\", comp)\n", "\n", "sim_emt = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", "sim_emt.set_system(system_emt)\n", @@ -174,9 +180,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'EMT_CIGRE_MV_withoutDG'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"EMT_CIGRE_MV_withoutDG\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim_powerflow = read_timeseries_csv(dpsim_result_file)" ] @@ -195,9 +201,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim_powerflow.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" @@ -225,9 +231,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'EMT_CIGRE_MV_withoutDG'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"EMT_CIGRE_MV_withoutDG\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -246,12 +252,16 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-3:] == 'V_0' and ts_name[:-2] != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-3:] == \"V_0\" and ts_name[:-2] != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", - " plt.plot(ts_dpsim_powerflow[ts_name].time, np.sqrt(2/3)*ts_dpsim_powerflow[ts_name].abs().values, label=ts_name)\n", - "plt.xlim([0,0.1])\n", + " plt.plot(\n", + " ts_dpsim_powerflow[ts_name].time,\n", + " np.sqrt(2 / 3) * ts_dpsim_powerflow[ts_name].abs().values,\n", + " label=ts_name,\n", + " )\n", + "plt.xlim([0, 0.1])\n", "plt.legend()\n", "plt.show()" ] @@ -270,9 +280,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.V_0':\n", - " print(ts_name + ': ' + str(ts_obj.values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".V_0\":\n", + " print(ts_name + \": \" + str(ts_obj.values[0]))" ] }, { @@ -289,9 +299,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.V_0':\n", - " print(ts_name + ': ' + str(ts_obj.values[-1:]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".V_0\":\n", + " print(ts_name + \": \" + str(ts_obj.values[-1:]))" ] }, { @@ -308,12 +318,12 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.I_0' and ts_name[:4]=='LOAD':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".I_0\" and ts_name[:4] == \"LOAD\":\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", - "#plt.xlim([0,0.1])\n", - "plt.legend(loc='upper right')\n", + "# plt.xlim([0,0.1])\n", + "plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -331,9 +341,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.I_0' and ts_name[:4]=='LOAD':\n", - " print(ts_name + ': ' + str(ts_obj.values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".I_0\" and ts_name[:4] == \"LOAD\":\n", + " print(ts_name + \": \" + str(ts_obj.values[0]))" ] }, { @@ -350,9 +360,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.I_0' and ts_name[:4]=='LOAD':\n", - " print(ts_name + ': ' + str(ts_obj.values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".I_0\" and ts_name[:4] == \"LOAD\":\n", + " print(ts_name + \": \" + str(ts_obj.values[-1]))" ] }, { @@ -372,8 +382,16 @@ "# load_I_3_p ref from CIM: P=225250, Q=139597\n", "# load_H_11_p ref from CIM: P=329800, Q=82656\n", "\n", - "load_I_3_p = ts_dpsim['N3.V_0'].values*ts_dpsim['LOAD-I-3.I_0'].values+ts_dpsim['N3.V_1'].values*ts_dpsim['LOAD-I-3.I_1'].values+ts_dpsim['N3.V_2'].values*ts_dpsim['LOAD-I-3.I_2'].values\n", - "load_H_11_p = ts_dpsim['N11.V_0'].values*ts_dpsim['LOAD-H-11.I_0'].values+ts_dpsim['N11.V_1'].values*ts_dpsim['LOAD-H-11.I_1'].values+ts_dpsim['N11.V_2'].values*ts_dpsim['LOAD-H-11.I_2'].values" + "load_I_3_p = (\n", + " ts_dpsim[\"N3.V_0\"].values * ts_dpsim[\"LOAD-I-3.I_0\"].values\n", + " + ts_dpsim[\"N3.V_1\"].values * ts_dpsim[\"LOAD-I-3.I_1\"].values\n", + " + ts_dpsim[\"N3.V_2\"].values * ts_dpsim[\"LOAD-I-3.I_2\"].values\n", + ")\n", + "load_H_11_p = (\n", + " ts_dpsim[\"N11.V_0\"].values * ts_dpsim[\"LOAD-H-11.I_0\"].values\n", + " + ts_dpsim[\"N11.V_1\"].values * ts_dpsim[\"LOAD-H-11.I_1\"].values\n", + " + ts_dpsim[\"N11.V_2\"].values * ts_dpsim[\"LOAD-H-11.I_2\"].values\n", + ")" ] }, { @@ -382,11 +400,11 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "plt.plot(ts_dpsim['N3.V_0'].time, load_I_3_p, label='load_I_3_p')\n", - "plt.plot(ts_dpsim['N11.V_0'].time, load_H_11_p, label='load_H_11_p')\n", - "#plt.xlim([0,0.01])\n", - "plt.legend(loc='upper right')\n", + "plt.figure(figsize=(12, 6))\n", + "plt.plot(ts_dpsim[\"N3.V_0\"].time, load_I_3_p, label=\"load_I_3_p\")\n", + "plt.plot(ts_dpsim[\"N11.V_0\"].time, load_H_11_p, label=\"load_H_11_p\")\n", + "# plt.xlim([0,0.01])\n", + "plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -404,8 +422,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Load-I-3.p' + ': ' + str(load_I_3_p[0]))\n", - "print('Load-H-11.p' + ': ' + str(load_H_11_p[0]))" + "print(\"Load-I-3.p\" + \": \" + str(load_I_3_p[0]))\n", + "print(\"Load-H-11.p\" + \": \" + str(load_H_11_p[0]))" ] }, { @@ -422,8 +440,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Load-I-3.p' + ': ' + str(load_I_3_p[-1]))\n", - "print('Load-H-11.p' + ': ' + str(load_H_11_p[-1]))" + "print(\"Load-I-3.p\" + \": \" + str(load_I_3_p[-1]))\n", + "print(\"Load-H-11.p\" + \": \" + str(load_H_11_p[-1]))" ] }, { @@ -440,12 +458,12 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.I_0' and ts_name[:4]!='LOAD':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".I_0\" and ts_name[:4] != \"LOAD\":\n", " plt.plot(ts_obj.time, ts_obj.values, label=ts_name)\n", - "#plt.xlim([0,0.1])\n", - "plt.legend(loc='upper right')\n", + "# plt.xlim([0,0.1])\n", + "plt.legend(loc=\"upper right\")\n", "plt.show()" ] }, @@ -463,9 +481,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.I_0' and ts_name[:4]!='LOAD':\n", - " print(ts_name + ': ' + str(ts_obj.values[0]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".I_0\" and ts_name[:4] != \"LOAD\":\n", + " print(ts_name + \": \" + str(ts_obj.values[0]))" ] }, { @@ -482,9 +500,9 @@ "metadata": {}, "outputs": [], "source": [ - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name[-4:] == '.I_0' and ts_name[:4]!='LOAD':\n", - " print(ts_name + ': ' + str(ts_obj.values[-1]))" + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name[-4:] == \".I_0\" and ts_name[:4] != \"LOAD\":\n", + " print(ts_name + \": \" + str(ts_obj.values[-1]))" ] } ], diff --git a/examples/Notebooks/Grids/IEEE_LV_powerflow.ipynb b/examples/Notebooks/Grids/IEEE_LV_powerflow.ipynb index 556dfcf315..891f000f96 100644 --- a/examples/Notebooks/Grids/IEEE_LV_powerflow.ipynb +++ b/examples/Notebooks/Grids/IEEE_LV_powerflow.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/IEEE_EU_LV/IEEE_EU_LV_reduced/'\n", - "filename = 'IEEE_EU_LV'\n", - "download_grid_data(filename+'_EQ.xml', url+'Rootnet_FULL_NE_13J16h_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'Rootnet_FULL_NE_13J16h_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'Rootnet_FULL_NE_13J16h_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/IEEE_EU_LV/IEEE_EU_LV_reduced/\"\n", + "filename = \"IEEE_EU_LV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"Rootnet_FULL_NE_13J16h_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"Rootnet_FULL_NE_13J16h_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"Rootnet_FULL_NE_13J16h_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -63,7 +65,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'IEEE_EU_LV_reduced'" + "sim_name = \"IEEE_EU_LV_reduced\"" ] }, { @@ -73,11 +75,13 @@ "outputs": [], "source": [ "reader = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.info, dpsimpy.LogLevel.off)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.NONE)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.NONE\n", + ")\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name() + '.V', 'v', node)\n", + " logger.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", "sim.set_system(system)\n", @@ -88,7 +92,7 @@ "sim.do_init_from_nodes_and_terminals(True)\n", "\n", "sim.add_logger(logger)\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -104,14 +108,14 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/'\n", - "logName = 'IEEE_EU_LV_reduced'\n", - "dpsim_result_file = path + logName + '.csv'\n", + "path = \"logs/\"\n", + "logName = \"IEEE_EU_LV_reduced\"\n", + "dpsim_result_file = path + logName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)\n", "\n", "# Fix for dpsim naming - TODO: unify dpsim notation in log file and update villas-dataprocessing accordingly\n", - "for ts,values in ts_dpsim.items():\n", + "for ts, values in ts_dpsim.items():\n", " values.name = values.name[:-2]" ] }, @@ -131,12 +135,12 @@ "import os\n", "import urllib\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Neplan/ReferenceGrids/IEEE_EU_LV.rlf'\n", - "neplan_result_file = 'reference-results/IEEE_EU_LV.rlf'\n", - "urllib.request.urlretrieve(url, neplan_result_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Neplan/ReferenceGrids/IEEE_EU_LV.rlf\"\n", + "neplan_result_file = \"reference-results/IEEE_EU_LV.rlf\"\n", + "urllib.request.urlretrieve(url, neplan_result_file)\n", "print(neplan_result_file)\n", "\n", "ts_NEPLAN = read_timeseries_NEPLAN_loadflow(neplan_result_file)\n", @@ -156,15 +160,19 @@ "metadata": {}, "outputs": [], "source": [ - "net_name='IEEE_EU_LV_reduced'\n", - "threshold=0.5\n", + "net_name = \"IEEE_EU_LV_reduced\"\n", + "threshold = 0.5\n", "\n", - "ts_NEPLAN_standardized=validationtools.convert_neplan_to_standard_timeseries(ts_NEPLAN)\n", - "#print([[ts_NEPLAN_standardized[i].name, ts_NEPLAN_standardized[i].values] for i in range(len(ts_NEPLAN_standardized))])\n", - "ts_dpsim_standardized=validationtools.convert_dpsim_to_standard_timeseries(ts_dpsim)\n", - "#print([[ts_dpsim_standardized[i].name, ts_dpsim_standardized[i].values] for i in range(len(ts_dpsim_standardized))])\n", - "res_err=validationtools.compare_timeseries(ts_NEPLAN_standardized,ts_dpsim_standardized)\n", - "validationtools.assert_modelica_results(net_name,res_err,threshold)" + "ts_NEPLAN_standardized = validationtools.convert_neplan_to_standard_timeseries(\n", + " ts_NEPLAN\n", + ")\n", + "# print([[ts_NEPLAN_standardized[i].name, ts_NEPLAN_standardized[i].values] for i in range(len(ts_NEPLAN_standardized))])\n", + "ts_dpsim_standardized = validationtools.convert_dpsim_to_standard_timeseries(ts_dpsim)\n", + "# print([[ts_dpsim_standardized[i].name, ts_dpsim_standardized[i].values] for i in range(len(ts_dpsim_standardized))])\n", + "res_err = validationtools.compare_timeseries(\n", + " ts_NEPLAN_standardized, ts_dpsim_standardized\n", + ")\n", + "validationtools.assert_modelica_results(net_name, res_err, threshold)" ] } ], diff --git a/examples/Notebooks/Grids/PF_CIGRE_MV_withDG.ipynb b/examples/Notebooks/Grids/PF_CIGRE_MV_withDG.ipynb index 895c85570c..8b093a85c0 100644 --- a/examples/Notebooks/Grids/PF_CIGRE_MV_withDG.ipynb +++ b/examples/Notebooks/Grids/PF_CIGRE_MV_withDG.ipynb @@ -30,18 +30,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_noLoad1_LeftFeeder_With_LoadFlow_Results/Rootnet_FULL_NE_28J17h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -63,7 +65,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'PF_CIGRE_MV_withDG'" + "sim_name = \"PF_CIGRE_MV_withDG\"" ] }, { @@ -79,30 +81,64 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "pv_active_power = 50e3 * int(int(4319.1e3 / 50e3) / 9)\n", - "pv_reactive_power = np.sqrt(np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2))\n", + "pv_reactive_power = np.sqrt(\n", + " np.power(pv_active_power / 1, 2) - np.power(pv_active_power, 2)\n", + ")\n", "\n", "for n in range(3, 12):\n", - " connection_node = system.node('N' + str(n))\n", - " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ('pv_' + connection_node.name(), 'pv_' + connection_node.name(), dpsimpy.LogLevel.debug, True)\n", - " pv.set_parameters(sys_omega=2 * np.pi * 50, sys_volt_nom=1500, p_ref=pv_active_power, q_ref=pv_reactive_power)\n", - " pv.set_controller_parameters(Kp_pll=0.25 / 10, Ki_pll=2 / 1000,\n", - " Kp_power_ctrl=0.001 / 10, Ki_power_ctrl=0.08 / 1000 ,\n", - " Kp_curr_ctrl=0.3 / 10, Ki_curr_ctrl=10 / 1000, omega_cutoff=2*np.pi*50)\n", - " pv.set_filter_parameters(Lf=0.002,Cf=789.3e-6,Rf=0.1,Rc=0.1)\n", - " pv.set_transformer_parameters(nom_voltage_end_1=20e3, nom_voltage_end_2=1500, rated_power = 5e6,\n", - " ratio_abs=20e3 / 1500, ratio_phase=0,resistance=0, inductance=0.928e-3)\n", - " pv.set_initial_state_values(p_init=450000.716605, q_init=-0.577218, phi_d_init=3854.197405 * 1000, phi_q_init=-0.003737 * 1000, gamma_d_init=128.892668 * 1000, gamma_q_init=23.068682 * 1000)\n", + " connection_node = system.node(\"N\" + str(n))\n", + " pv = dpsimpy.sp.ph1.AvVoltageSourceInverterDQ(\n", + " \"pv_\" + connection_node.name(),\n", + " \"pv_\" + connection_node.name(),\n", + " dpsimpy.LogLevel.debug,\n", + " True,\n", + " )\n", + " pv.set_parameters(\n", + " sys_omega=2 * np.pi * 50,\n", + " sys_volt_nom=1500,\n", + " p_ref=pv_active_power,\n", + " q_ref=pv_reactive_power,\n", + " )\n", + " pv.set_controller_parameters(\n", + " Kp_pll=0.25 / 10,\n", + " Ki_pll=2 / 1000,\n", + " Kp_power_ctrl=0.001 / 10,\n", + " Ki_power_ctrl=0.08 / 1000,\n", + " Kp_curr_ctrl=0.3 / 10,\n", + " Ki_curr_ctrl=10 / 1000,\n", + " omega_cutoff=2 * np.pi * 50,\n", + " )\n", + " pv.set_filter_parameters(Lf=0.002, Cf=789.3e-6, Rf=0.1, Rc=0.1)\n", + " pv.set_transformer_parameters(\n", + " nom_voltage_end_1=20e3,\n", + " nom_voltage_end_2=1500,\n", + " rated_power=5e6,\n", + " ratio_abs=20e3 / 1500,\n", + " ratio_phase=0,\n", + " resistance=0,\n", + " inductance=0.928e-3,\n", + " )\n", + " pv.set_initial_state_values(\n", + " p_init=450000.716605,\n", + " q_init=-0.577218,\n", + " phi_d_init=3854.197405 * 1000,\n", + " phi_q_init=-0.003737 * 1000,\n", + " gamma_d_init=128.892668 * 1000,\n", + " gamma_q_init=23.068682 * 1000,\n", + " )\n", " system.add(pv)\n", " system.connect_component(pv, [connection_node])\n", "\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name() + '.V', 'v', node)\n", + " logger.log_attribute(node.name() + \".V\", \"v\", node)\n", "\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", "sim.set_system(system)\n", @@ -113,7 +149,7 @@ "sim.do_init_from_nodes_and_terminals(True)\n", "\n", "sim.add_logger(logger)\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -129,9 +165,9 @@ "metadata": {}, "outputs": [], "source": [ - "modelName = 'PF_CIGRE_MV_withDG'\n", - "path = 'logs/' + modelName + '/'\n", - "dpsim_result_file = path + modelName + '.csv'\n", + "modelName = \"PF_CIGRE_MV_withDG\"\n", + "path = \"logs/\" + modelName + \"/\"\n", + "dpsim_result_file = path + modelName + \".csv\"\n", "\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] @@ -149,9 +185,9 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,6))\n", - "for ts_name, ts_obj in ts_dpsim.items():\n", - " if ts_name != 'N0.V':\n", + "plt.figure(figsize=(12, 6))\n", + "for ts_name, ts_obj in ts_dpsim.items():\n", + " if ts_name != \"N0.V\":\n", " plt.plot(ts_obj.time, ts_obj.abs().values, label=ts_name)\n", "plt.legend()\n", "plt.show()" diff --git a/examples/Notebooks/Grids/SP_SMIB_SynGenTrStab_KundurExample1.ipynb b/examples/Notebooks/Grids/SP_SMIB_SynGenTrStab_KundurExample1.ipynb index 2e3a54927e..5b0df15b4c 100644 --- a/examples/Notebooks/Grids/SP_SMIB_SynGenTrStab_KundurExample1.ipynb +++ b/examples/Notebooks/Grids/SP_SMIB_SynGenTrStab_KundurExample1.ipynb @@ -29,13 +29,18 @@ "import os\n", "import subprocess\n", "\n", - "#%matplotlib widget\n", + "# %matplotlib widget\n", "\n", - "name = 'SP_SynGenTrStab_SMIB_Fault_KundurExample1'\n", + "name = \"SP_SynGenTrStab_SMIB_Fault_KundurExample1\"\n", "\n", - "dpsim_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", + "dpsim_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", "\n", - "path_exec = dpsim_path + '/build/dpsim/examples/cxx/'\n", + "path_exec = dpsim_path + \"/build/dpsim/examples/cxx/\"\n", "\n", "timestep = 100e-6" ] @@ -53,7 +58,11 @@ "metadata": {}, "outputs": [], "source": [ - "sim = subprocess.Popen([path_exec+name, '--name', name, '--timestep', str(timestep)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + "sim = subprocess.Popen(\n", + " [path_exec + name, \"--name\", name, \"--timestep\", str(timestep)],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + ")\n", "print(sim.communicate()[0].decode())" ] }, @@ -70,9 +79,9 @@ "metadata": {}, "outputs": [], "source": [ - "model_name = 'SynGenTrStab_SMIB_Fault_KundurExample1'\n", - "path_ref = 'logs/' + 'SP_' + model_name + '_SP/'\n", - "dpsim_result_file_ref = path_ref + 'SP_' + model_name + '_SP.csv'\n", + "model_name = \"SynGenTrStab_SMIB_Fault_KundurExample1\"\n", + "path_ref = \"logs/\" + \"SP_\" + model_name + \"_SP/\"\n", + "dpsim_result_file_ref = path_ref + \"SP_\" + model_name + \"_SP.csv\"\n", "ts_dpsim_ref = read_timeseries_csv(dpsim_result_file_ref)" ] }, @@ -92,14 +101,27 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/Kundur2-Example1/d_kundur2_example1_dpsim.out'\n", - "local_file = 'reference-results/d_kundur2_example1_dpsim.out'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/Kundur2-Example1/d_kundur2_example1_dpsim.out\"\n", + "local_file = \"reference-results/d_kundur2_example1_dpsim.out\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", - "timeseries_names_psat = ['delta_Syn_1', 'omega_Syn_1', 'theta_Bus1', 'theta_Bus2', 'theta_Bus3', 'V_Bus1', 'V_Bus2', 'V_Bus3', 'pm_Syn_1', 'vf_Syn_1', 'p_Syn_1', 'q_Syn_1']\n", + "timeseries_names_psat = [\n", + " \"delta_Syn_1\",\n", + " \"omega_Syn_1\",\n", + " \"theta_Bus1\",\n", + " \"theta_Bus2\",\n", + " \"theta_Bus3\",\n", + " \"V_Bus1\",\n", + " \"V_Bus2\",\n", + " \"V_Bus3\",\n", + " \"pm_Syn_1\",\n", + " \"vf_Syn_1\",\n", + " \"p_Syn_1\",\n", + " \"q_Syn_1\",\n", + "]\n", "\n", "ts_psat = read_timeseries_PSAT(local_file, timeseries_names_psat)" ] @@ -117,10 +139,10 @@ "metadata": {}, "outputs": [], "source": [ - "vbase = 400e3 # for p.u. conversion\n", - "deg_to_rad = np.pi/180\n", + "vbase = 400e3 # for p.u. conversion\n", + "deg_to_rad = np.pi / 180\n", "sbase = 100e6\n", - "omega_base = 2*np.pi*60\n", + "omega_base = 2 * np.pi * 60\n", "sgen = 2220e6" ] }, @@ -139,11 +161,11 @@ "source": [ "timestep_common = 100e-6\n", "\n", - "t_begin=0\n", - "t_end=10\n", + "t_begin = 0\n", + "t_end = 10\n", "\n", - "begin_idx = int(t_begin/timestep_common)\n", - "end_idx= int(t_end/timestep_common)" + "begin_idx = int(t_begin / timestep_common)\n", + "end_idx = int(t_end / timestep_common)" ] }, { @@ -159,12 +181,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['v1', 'v2', 'v3']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx], label=name + ' SP DPsim')\n", - "for name in ['V_Bus1', 'V_Bus2', 'V_Bus3']:\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx]*vbase, label=name + ' SP PSAT', linestyle='--')\n", + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx],\n", + " label=name + \" SP DPsim\",\n", + " )\n", + "for name in [\"V_Bus1\", \"V_Bus2\", \"V_Bus3\"]:\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx] * vbase,\n", + " label=name + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -182,12 +213,25 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['v1', 'v2', 'v3']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).phase().values[begin_idx:end_idx]*deg_to_rad, label=name + ' phase SP DPsim')\n", - "for name in ['theta_Bus1', 'theta_Bus2', 'theta_Bus3']:\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx], label=name + ' SP PSAT', linestyle='--')\n", + "for name in [\"v1\", \"v2\", \"v3\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name]\n", + " .interpolate(timestep_common)\n", + " .phase()\n", + " .values[begin_idx:end_idx]\n", + " * deg_to_rad,\n", + " label=name + \" phase SP DPsim\",\n", + " )\n", + "for name in [\"theta_Bus1\", \"theta_Bus2\", \"theta_Bus3\"]:\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=name + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -205,13 +249,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['Ep']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx], label=name + ' SP DPsim')\n", - "for name in ['vf_Syn_1']:\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx]*vbase, label=name + ' SP PSAT', linestyle='--')\n", - "plt.ylim([0.5*vbase,1.5*vbase])\n", + "for name in [\"Ep\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx],\n", + " label=name + \" SP DPsim\",\n", + " )\n", + "for name in [\"vf_Syn_1\"]:\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx] * vbase,\n", + " label=name + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", + "plt.ylim([0.5 * vbase, 1.5 * vbase])\n", "plt.legend()\n", "plt.show()" ] @@ -229,13 +282,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", - "for name in ['v_fault']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx], label=name + 'SP DPsim')\n", - "for name in ['i_fault']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx], label=name + 'SP DPsim')\n", + "plt.figure(figsize=(12, 8))\n", + "for name in [\"v_fault\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx],\n", + " label=name + \"SP DPsim\",\n", + " )\n", + "for name in [\"i_fault\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).abs().values[begin_idx:end_idx],\n", + " label=name + \"SP DPsim\",\n", + " )\n", "\n", - "plt.xlim([0.4,0.6])\n", + "plt.xlim([0.4, 0.6])\n", "plt.legend()\n", "plt.show()" ] @@ -253,12 +314,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['P_mech']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx], label=name + ' SP DPsim')\n", - "for name in ['pm_Syn_1']:\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx]*sbase, label=name + ' SP PSAT', linestyle='--')\n", + "for name in [\"P_mech\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=name + \" SP DPsim\",\n", + " )\n", + "for name in [\"pm_Syn_1\"]:\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx] * sbase,\n", + " label=name + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -276,13 +346,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['P_elec']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx], label=name + ' SP DPsim')\n", - "for name in ['p_Syn_1']:\n", - " ts_psat[name].values = ts_psat[name].values*sbase\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx], label=name + ' SP PSAT', linestyle='--')\n", + "for name in [\"P_elec\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=name + \" SP DPsim\",\n", + " )\n", + "for name in [\"p_Syn_1\"]:\n", + " ts_psat[name].values = ts_psat[name].values * sbase\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=name + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -300,13 +379,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['Q_elec']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx], label=name + ' SP DPsim')\n", - "for name in ['q_Syn_1']:\n", - " ts_psat[name].values = ts_psat[name].values*sbase\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx], label=name + ' SP PSAT', linestyle='--')\n", + "for name in [\"Q_elec\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=name + \" SP DPsim\",\n", + " )\n", + "for name in [\"q_Syn_1\"]:\n", + " ts_psat[name].values = ts_psat[name].values * sbase\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=name + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -324,13 +412,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['wr_gen']:\n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx], label='$\\omega _r$' + ' SP DPsim')\n", - "for name in ['omega_Syn_1']:\n", - " ts_psat[name].values = ts_psat[name].values*omega_base\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx], label='$\\omega _r$' + ' SP PSAT', linestyle='--')\n", + "for name in [\"wr_gen\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=\"$\\omega _r$\" + \" SP DPsim\",\n", + " )\n", + "for name in [\"omega_Syn_1\"]:\n", + " ts_psat[name].values = ts_psat[name].values * omega_base\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=\"$\\omega _r$\" + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -348,12 +445,21 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,8))\n", + "plt.figure(figsize=(12, 8))\n", "\n", - "for name in ['delta_r_gen']: \n", - " plt.plot(ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx], label='$\\delta _r$' + ' SP DPsim')\n", - "for name in ['delta_Syn_1']:\n", - " plt.plot(ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx], ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx], label='$\\delta _r$' + ' SP PSAT', linestyle='--')\n", + "for name in [\"delta_r_gen\"]:\n", + " plt.plot(\n", + " ts_dpsim_ref[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_dpsim_ref[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=\"$\\delta _r$\" + \" SP DPsim\",\n", + " )\n", + "for name in [\"delta_Syn_1\"]:\n", + " plt.plot(\n", + " ts_psat[name].interpolate(timestep_common).time[begin_idx:end_idx],\n", + " ts_psat[name].interpolate(timestep_common).values[begin_idx:end_idx],\n", + " label=\"$\\delta _r$\" + \" SP PSAT\",\n", + " linestyle=\"--\",\n", + " )\n", "plt.legend()\n", "plt.show()" ] @@ -371,14 +477,38 @@ "metadata": {}, "outputs": [], "source": [ - "p_elec_diff = ts_dpsim_ref['P_elec'].rmse(ts_dpsim_ref['P_elec'].interpolate(timestep_common), ts_psat['p_Syn_1'].interpolate(timestep_common))\n", - "print('{:.3f} MVA, which is {:.3f}% of nominal Sgen = {:.2f} MVA'.format(p_elec_diff/1e6, p_elec_diff/sgen*100, sgen/1e6))\n", - "q_elec_diff = ts_dpsim_ref['Q_elec'].rmse(ts_dpsim_ref['Q_elec'].interpolate(timestep_common), ts_psat['q_Syn_1'].interpolate(timestep_common))\n", - "print('{:.3f} MVA, which is {:.3}% of nominal Sgen = {:.2f} MVA'.format(q_elec_diff/1e6, q_elec_diff/sgen*100,sgen/1e6))\n", - "omega_r_diff = ts_dpsim_ref['wr_gen'].rmse(ts_dpsim_ref['wr_gen'].interpolate(timestep_common), ts_psat['omega_Syn_1'].interpolate(timestep_common))\n", - "print('{:.3f} 1/s, which is {:.3}% of nominal omega {:.2f} 1/s'.format(omega_r_diff, omega_r_diff/omega_base*100, omega_base))\n", - "delta_r_gen_diff = ts_dpsim_ref['delta_r_gen'].rmse(ts_dpsim_ref['delta_r_gen'].interpolate(timestep_common), ts_psat['delta_Syn_1'].interpolate(timestep_common))\n", - "print('{:.3} rad'.format(delta_r_gen_diff))" + "p_elec_diff = ts_dpsim_ref[\"P_elec\"].rmse(\n", + " ts_dpsim_ref[\"P_elec\"].interpolate(timestep_common),\n", + " ts_psat[\"p_Syn_1\"].interpolate(timestep_common),\n", + ")\n", + "print(\n", + " \"{:.3f} MVA, which is {:.3f}% of nominal Sgen = {:.2f} MVA\".format(\n", + " p_elec_diff / 1e6, p_elec_diff / sgen * 100, sgen / 1e6\n", + " )\n", + ")\n", + "q_elec_diff = ts_dpsim_ref[\"Q_elec\"].rmse(\n", + " ts_dpsim_ref[\"Q_elec\"].interpolate(timestep_common),\n", + " ts_psat[\"q_Syn_1\"].interpolate(timestep_common),\n", + ")\n", + "print(\n", + " \"{:.3f} MVA, which is {:.3}% of nominal Sgen = {:.2f} MVA\".format(\n", + " q_elec_diff / 1e6, q_elec_diff / sgen * 100, sgen / 1e6\n", + " )\n", + ")\n", + "omega_r_diff = ts_dpsim_ref[\"wr_gen\"].rmse(\n", + " ts_dpsim_ref[\"wr_gen\"].interpolate(timestep_common),\n", + " ts_psat[\"omega_Syn_1\"].interpolate(timestep_common),\n", + ")\n", + "print(\n", + " \"{:.3f} 1/s, which is {:.3}% of nominal omega {:.2f} 1/s\".format(\n", + " omega_r_diff, omega_r_diff / omega_base * 100, omega_base\n", + " )\n", + ")\n", + "delta_r_gen_diff = ts_dpsim_ref[\"delta_r_gen\"].rmse(\n", + " ts_dpsim_ref[\"delta_r_gen\"].interpolate(timestep_common),\n", + " ts_psat[\"delta_Syn_1\"].interpolate(timestep_common),\n", + ")\n", + "print(\"{:.3} rad\".format(delta_r_gen_diff))" ] }, { @@ -394,10 +524,10 @@ "metadata": {}, "outputs": [], "source": [ - "assert(p_elec_diff/1e6<0.6)\n", - "assert(q_elec_diff/1e6<4)\n", - "assert(omega_r_diff<0.002)\n", - "assert(delta_r_gen_diff<2e-4)" + "assert p_elec_diff / 1e6 < 0.6\n", + "assert q_elec_diff / 1e6 < 4\n", + "assert omega_r_diff < 0.002\n", + "assert delta_r_gen_diff < 2e-4" ] }, { diff --git a/examples/Notebooks/Grids/SP_WSCC9bus_SG4thOrder_Fault_PSAT_Validation.ipynb b/examples/Notebooks/Grids/SP_WSCC9bus_SG4thOrder_Fault_PSAT_Validation.ipynb index 3c506a702d..c62d95a086 100644 --- a/examples/Notebooks/Grids/SP_WSCC9bus_SG4thOrder_Fault_PSAT_Validation.ipynb +++ b/examples/Notebooks/Grids/SP_WSCC9bus_SG4thOrder_Fault_PSAT_Validation.ipynb @@ -27,42 +27,49 @@ "import requests\n", "import urllib.request\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "#%matplotlib widget\n", "\n", - "PEAK1PH_TO_RMS3PH=np.sqrt(3./2.)\n", + "# %matplotlib widget\n", + "\n", + "PEAK1PH_TO_RMS3PH = np.sqrt(3.0 / 2.0)\n", "\n", - "name_exec = 'SP_WSCC9bus_SGReducedOrderVBR'\n", + "name_exec = \"SP_WSCC9bus_SGReducedOrderVBR\"\n", "\n", - "order_names_list = ['4th'] # ['3rd', '4th', '6th']\n", - "order_options_list = ['sgType=4'] # ['sgType=3', 'sgType=4', 'sgType=6b']\n", - "sim_names_list = [name_exec + '_' + order_name for order_name in order_names_list]\n", + "order_names_list = [\"4th\"] # ['3rd', '4th', '6th']\n", + "order_options_list = [\"sgType=4\"] # ['sgType=3', 'sgType=4', 'sgType=6b']\n", + "sim_names_list = [name_exec + \"_\" + order_name for order_name in order_names_list]\n", "num_orders = len(order_names_list)\n", "\n", "timestep = 1e-3\n", "duration = 30\n", "\n", - "view_time_interval = [0.1,1.0]\n", + "view_time_interval = [0.1, 1.0]\n", "\n", - "root_path = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')\n", + "root_path = (\n", + " subprocess.Popen([\"git\", \"rev-parse\", \"--show-toplevel\"], stdout=subprocess.PIPE)\n", + " .communicate()[0]\n", + " .rstrip()\n", + " .decode(\"utf-8\")\n", + ")\n", "\n", - "path_exec = root_path + '/build/dpsim/examples/cxx/'\n", + "path_exec = root_path + \"/build/dpsim/examples/cxx/\"\n", "\n", - "cim_file = 'WSCC-09_Dyn_Fourth'\n", + "cim_file = \"WSCC-09_Dyn_Fourth\"\n", "\n", - "cim_url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth'\n", - "download_grid_data(cim_file+'_EQ.xml', cim_url+'_EQ.xml')\n", - "download_grid_data(cim_file+'_TP.xml', cim_url+'_TP.xml')\n", - "download_grid_data(cim_file+'_SV.xml', cim_url+'_SV.xml')\n", - "download_grid_data(cim_file+'_DI.xml', cim_url+'_DI.xml')\n", + "cim_url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth\"\n", + "download_grid_data(cim_file + \"_EQ.xml\", cim_url + \"_EQ.xml\")\n", + "download_grid_data(cim_file + \"_TP.xml\", cim_url + \"_TP.xml\")\n", + "download_grid_data(cim_file + \"_SV.xml\", cim_url + \"_SV.xml\")\n", + "download_grid_data(cim_file + \"_DI.xml\", cim_url + \"_DI.xml\")\n", "\n", - "psat_results_url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/WSCC-9bus/d_009_fault_dpsim_4th_order.out'\n", - "psat_results_file = 'd_009_fault_dpsim_4th_order.out'\n", - "urllib.request.urlretrieve(psat_results_url, psat_results_file) " + "psat_results_url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/WSCC-9bus/d_009_fault_dpsim_4th_order.out\"\n", + "psat_results_file = \"d_009_fault_dpsim_4th_order.out\"\n", + "urllib.request.urlretrieve(psat_results_url, psat_results_file)" ] }, { @@ -80,7 +87,25 @@ "outputs": [], "source": [ "for order_idx in range(num_orders):\n", - " sim = subprocess.Popen([path_exec+name_exec, '--name', sim_names_list[order_idx], '--timestep', str(timestep), '--duration', str(duration), cim_file +'_DI.xml', cim_file +'_EQ.xml', cim_file +'_SV.xml', cim_file +'_TP.xml', '--option', order_options_list[order_idx]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n", + " sim = subprocess.Popen(\n", + " [\n", + " path_exec + name_exec,\n", + " \"--name\",\n", + " sim_names_list[order_idx],\n", + " \"--timestep\",\n", + " str(timestep),\n", + " \"--duration\",\n", + " str(duration),\n", + " cim_file + \"_DI.xml\",\n", + " cim_file + \"_EQ.xml\",\n", + " cim_file + \"_SV.xml\",\n", + " cim_file + \"_TP.xml\",\n", + " \"--option\",\n", + " order_options_list[order_idx],\n", + " ],\n", + " stdout=subprocess.PIPE,\n", + " stderr=subprocess.STDOUT,\n", + " )\n", " print(sim.communicate()[0].decode())" ] }, @@ -100,9 +125,9 @@ "source": [ "ts_dpsim = []\n", "for order_idx in range(num_orders):\n", - " path = 'logs/' + sim_names_list[order_idx] + '/'\n", + " path = \"logs/\" + sim_names_list[order_idx] + \"/\"\n", " logName = sim_names_list[order_idx]\n", - " logFilename = path + logName + '.csv'\n", + " logFilename = path + logName + \".csv\"\n", " print(logFilename)\n", " ts_dpsim.append(rt.read_timeseries_dpsim(logFilename))" ] @@ -121,20 +146,56 @@ "metadata": {}, "outputs": [], "source": [ - "syngen_power_name_dpsim_list = ['GEN1.Te', 'GEN2.Te', 'GEN3.Te']\n", - "syngen_power_name_psat_list = ['p_Syn_1', 'p_Syn_2', 'p_Syn_3']\n", + "syngen_power_name_dpsim_list = [\"GEN1.Te\", \"GEN2.Te\", \"GEN3.Te\"]\n", + "syngen_power_name_psat_list = [\"p_Syn_1\", \"p_Syn_2\", \"p_Syn_3\"]\n", "\n", - "syngen_omega_name_dpsim_list = ['GEN1.omega', 'GEN2.omega', 'GEN3.omega']\n", - "syngen_omega_name_psat_list = ['omega_Syn_1', 'omega_Syn_2', 'omega_Syn_3']\n", + "syngen_omega_name_dpsim_list = [\"GEN1.omega\", \"GEN2.omega\", \"GEN3.omega\"]\n", + "syngen_omega_name_psat_list = [\"omega_Syn_1\", \"omega_Syn_2\", \"omega_Syn_3\"]\n", "\n", - "syngen_delta_name_dpsim_list = ['GEN1.delta', 'GEN2.delta', 'GEN3.delta']\n", - "syngen_delta_name_psat_list = ['delta_Syn_1', 'delta_Syn_2', 'delta_Syn_3']\n", + "syngen_delta_name_dpsim_list = [\"GEN1.delta\", \"GEN2.delta\", \"GEN3.delta\"]\n", + "syngen_delta_name_psat_list = [\"delta_Syn_1\", \"delta_Syn_2\", \"delta_Syn_3\"]\n", "\n", - "bus_volt_name_dpsim_list = ['BUS1.V', 'BUS2.V', 'BUS3.V', 'BUS4.V', 'BUS5.V', 'BUS6.V', 'BUS7.V', 'BUS8.V', 'BUS9.V']\n", - "bus_volt_name_psat_list = ['V_Bus 1', 'V_Bus 2', 'V_Bus 3', 'V_Bus 4', 'V_Bus 5', 'V_Bus 6', 'V_Bus 7', 'V_Bus 8', 'V_Bus 9']\n", - "bus_angle_name_psat_list = ['theta_Bus 1', 'theta_Bus 2', 'theta_Bus 3', 'theta_Bus 4', 'theta_Bus 5', 'theta_Bus 6', 'theta_Bus 7', 'theta_Bus 8', 'theta_Bus 9']\n", + "bus_volt_name_dpsim_list = [\n", + " \"BUS1.V\",\n", + " \"BUS2.V\",\n", + " \"BUS3.V\",\n", + " \"BUS4.V\",\n", + " \"BUS5.V\",\n", + " \"BUS6.V\",\n", + " \"BUS7.V\",\n", + " \"BUS8.V\",\n", + " \"BUS9.V\",\n", + "]\n", + "bus_volt_name_psat_list = [\n", + " \"V_Bus 1\",\n", + " \"V_Bus 2\",\n", + " \"V_Bus 3\",\n", + " \"V_Bus 4\",\n", + " \"V_Bus 5\",\n", + " \"V_Bus 6\",\n", + " \"V_Bus 7\",\n", + " \"V_Bus 8\",\n", + " \"V_Bus 9\",\n", + "]\n", + "bus_angle_name_psat_list = [\n", + " \"theta_Bus 1\",\n", + " \"theta_Bus 2\",\n", + " \"theta_Bus 3\",\n", + " \"theta_Bus 4\",\n", + " \"theta_Bus 5\",\n", + " \"theta_Bus 6\",\n", + " \"theta_Bus 7\",\n", + " \"theta_Bus 8\",\n", + " \"theta_Bus 9\",\n", + "]\n", "\n", - "timeseries_names_psat = syngen_power_name_psat_list+syngen_omega_name_psat_list+syngen_delta_name_psat_list+bus_volt_name_psat_list+bus_angle_name_psat_list\n", + "timeseries_names_psat = (\n", + " syngen_power_name_psat_list\n", + " + syngen_omega_name_psat_list\n", + " + syngen_delta_name_psat_list\n", + " + bus_volt_name_psat_list\n", + " + bus_angle_name_psat_list\n", + ")\n", "\n", "ts_psat = []\n", "for order_idx in range(num_orders):\n", @@ -156,18 +217,33 @@ "outputs": [], "source": [ "for order_idx in range(num_orders):\n", - " plt.figure(figsize=(12,9))\n", - " #plt.subplot(num_orders,1,order_idx+1)\n", + " plt.figure(figsize=(12, 9))\n", + " # plt.subplot(num_orders,1,order_idx+1)\n", " for syngen_omega_name_dpsim in syngen_omega_name_dpsim_list:\n", - " plt.plot(ts_dpsim[order_idx][syngen_omega_name_dpsim].time, ts_dpsim[order_idx][syngen_omega_name_dpsim].values, label=syngen_omega_name_dpsim+', '+order_names_list[order_idx]+' (dpsim)')\n", + " plt.plot(\n", + " ts_dpsim[order_idx][syngen_omega_name_dpsim].time,\n", + " ts_dpsim[order_idx][syngen_omega_name_dpsim].values,\n", + " label=syngen_omega_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " )\n", " for syngen_omega_name_psat in syngen_omega_name_psat_list:\n", - " plt.plot(ts_psat[order_idx][syngen_omega_name_psat].time, ts_psat[order_idx][syngen_omega_name_psat].values, label=syngen_omega_name_psat+', '+order_names_list[order_idx]+' (psat)', linestyle='--')\n", - " \n", - " #plt.ylim([0.99,1.02])\n", + " plt.plot(\n", + " ts_psat[order_idx][syngen_omega_name_psat].time,\n", + " ts_psat[order_idx][syngen_omega_name_psat].values,\n", + " label=syngen_omega_name_psat\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "\n", + " # plt.ylim([0.99,1.02])\n", " plt.xlim(view_time_interval)\n", - " \n", - " plt.xlabel('time (s)')\n", - " plt.ylabel('mechanical speed (p.u)')\n", + "\n", + " plt.xlabel(\"time (s)\")\n", + " plt.ylabel(\"mechanical speed (p.u)\")\n", " plt.legend()" ] }, @@ -185,17 +261,32 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,9))\n", + "plt.figure(figsize=(12, 9))\n", "for order_idx in range(num_orders):\n", - " plt.subplot(num_orders,1,order_idx+1)\n", + " plt.subplot(num_orders, 1, order_idx + 1)\n", " for syngen_delta_name_dpsim in syngen_delta_name_dpsim_list:\n", - " plt.plot(ts_dpsim[order_idx][syngen_delta_name_dpsim].time, ts_dpsim[order_idx][syngen_delta_name_dpsim].values/np.pi*180, label=syngen_delta_name_dpsim+', '+order_names_list[order_idx]+' (dpsim)')\n", + " plt.plot(\n", + " ts_dpsim[order_idx][syngen_delta_name_dpsim].time,\n", + " ts_dpsim[order_idx][syngen_delta_name_dpsim].values / np.pi * 180,\n", + " label=syngen_delta_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " )\n", " for syngen_delta_name_psat in syngen_delta_name_psat_list:\n", - " plt.plot(ts_psat[order_idx][syngen_delta_name_psat].time, ts_psat[order_idx][syngen_delta_name_psat].values/np.pi*180, label=syngen_delta_name_psat+', '+order_names_list[order_idx]+' (psat)', linestyle='--')\n", - " \n", + " plt.plot(\n", + " ts_psat[order_idx][syngen_delta_name_psat].time,\n", + " ts_psat[order_idx][syngen_delta_name_psat].values / np.pi * 180,\n", + " label=syngen_delta_name_psat\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "\n", " plt.xlim(view_time_interval)\n", - " plt.xlabel('time (s)')\n", - " plt.ylabel('rotor angle (rad)')\n", + " plt.xlabel(\"time (s)\")\n", + " plt.ylabel(\"rotor angle (rad)\")\n", " plt.legend()" ] }, @@ -214,16 +305,43 @@ "outputs": [], "source": [ "for order_idx in range(num_orders):\n", - " plt.figure(figsize=(12,9))\n", - " #plt.subplot(num_orders,1,order_idx+1)\n", + " plt.figure(figsize=(12, 9))\n", + " # plt.subplot(num_orders,1,order_idx+1)\n", " for syngen_delta_name_dpsim in syngen_delta_name_dpsim_list:\n", - " plt.plot(ts_dpsim[order_idx][syngen_delta_name_dpsim].time, (ts_dpsim[order_idx][syngen_delta_name_dpsim].values-ts_dpsim[order_idx]['GEN1.delta'].values+ts_dpsim[order_idx]['GEN1.delta'].values[0])/np.pi*180, label=syngen_delta_name_dpsim+', '+order_names_list[order_idx]+' (dpsim)')\n", + " plt.plot(\n", + " ts_dpsim[order_idx][syngen_delta_name_dpsim].time,\n", + " (\n", + " ts_dpsim[order_idx][syngen_delta_name_dpsim].values\n", + " - ts_dpsim[order_idx][\"GEN1.delta\"].values\n", + " + ts_dpsim[order_idx][\"GEN1.delta\"].values[0]\n", + " )\n", + " / np.pi\n", + " * 180,\n", + " label=syngen_delta_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " )\n", " for syngen_delta_name_psat in syngen_delta_name_psat_list:\n", - " plt.plot(ts_psat[order_idx][syngen_delta_name_psat].time, (ts_psat[order_idx][syngen_delta_name_psat].values-ts_psat[order_idx]['delta_Syn_3'].values+ts_psat[order_idx]['delta_Syn_3'].values[0])/np.pi*180, label=syngen_delta_name_psat+', '+order_names_list[order_idx]+' (psat)', linestyle='--')\n", - " \n", + " plt.plot(\n", + " ts_psat[order_idx][syngen_delta_name_psat].time,\n", + " (\n", + " ts_psat[order_idx][syngen_delta_name_psat].values\n", + " - ts_psat[order_idx][\"delta_Syn_3\"].values\n", + " + ts_psat[order_idx][\"delta_Syn_3\"].values[0]\n", + " )\n", + " / np.pi\n", + " * 180,\n", + " label=syngen_delta_name_psat\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "\n", " plt.xlim(view_time_interval)\n", - " plt.xlabel('time (s)')\n", - " plt.ylabel('rotor angle (rad)')\n", + " plt.xlabel(\"time (s)\")\n", + " plt.ylabel(\"rotor angle (rad)\")\n", " plt.legend()" ] }, @@ -241,24 +359,62 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,12))\n", + "plt.figure(figsize=(12, 12))\n", "for order_idx in range(num_orders):\n", - " plt.subplot(num_orders,1,order_idx+1)\n", + " plt.subplot(num_orders, 1, order_idx + 1)\n", " for bus_volt_name_dpsim in bus_volt_name_dpsim_list:\n", - " if bus_volt_name_dpsim == 'BUS1.V':\n", - " plt.plot(ts_dpsim[order_idx][bus_volt_name_dpsim].time, ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values/16.5e3, label=bus_volt_name_dpsim +', '+order_names_list[order_idx]+' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", - " elif bus_volt_name_dpsim == 'BUS2.V':\n", - " plt.plot(ts_dpsim[order_idx][bus_volt_name_dpsim].time, ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values/18e3, label=bus_volt_name_dpsim +', '+order_names_list[order_idx]+' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", - " elif bus_volt_name_dpsim == 'BUS3.V':\n", - " plt.plot(ts_dpsim[order_idx][bus_volt_name_dpsim].time, ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values/13.8e3, label=bus_volt_name_dpsim +', '+order_names_list[order_idx]+' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", + " if bus_volt_name_dpsim == \"BUS1.V\":\n", + " plt.plot(\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].time,\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values / 16.5e3,\n", + " label=bus_volt_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", + " elif bus_volt_name_dpsim == \"BUS2.V\":\n", + " plt.plot(\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].time,\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values / 18e3,\n", + " label=bus_volt_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", + " elif bus_volt_name_dpsim == \"BUS3.V\":\n", + " plt.plot(\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].time,\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values / 13.8e3,\n", + " label=bus_volt_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", " else:\n", - " plt.plot(ts_dpsim[order_idx][bus_volt_name_dpsim].time, ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values/230e3, label=bus_volt_name_dpsim +', '+order_names_list[order_idx]+' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", + " plt.plot(\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].time,\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].abs().values / 230e3,\n", + " label=bus_volt_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", " for bus_volt_name_psat in bus_volt_name_psat_list:\n", - " plt.plot(ts_psat[order_idx][bus_volt_name_psat].time, ts_psat[order_idx][bus_volt_name_psat].values, label=bus_volt_name_psat +', '+order_names_list[order_idx]+' (psat)', linestyle='--', color='C'+str(bus_volt_name_psat_list.index(bus_volt_name_psat)))\n", - " \n", + " plt.plot(\n", + " ts_psat[order_idx][bus_volt_name_psat].time,\n", + " ts_psat[order_idx][bus_volt_name_psat].values,\n", + " label=bus_volt_name_psat + \", \" + order_names_list[order_idx] + \" (psat)\",\n", + " linestyle=\"--\",\n", + " color=\"C\" + str(bus_volt_name_psat_list.index(bus_volt_name_psat)),\n", + " )\n", + "\n", " plt.xlim(view_time_interval)\n", - " plt.xlabel('time (s)')\n", - " plt.ylabel('voltage (p.u.)')\n", + " plt.xlabel(\"time (s)\")\n", + " plt.ylabel(\"voltage (p.u.)\")\n", " plt.legend()" ] }, @@ -276,17 +432,29 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,12))\n", + "plt.figure(figsize=(12, 12))\n", "for order_idx in range(num_orders):\n", - " plt.subplot(num_orders,1,order_idx+1)\n", + " plt.subplot(num_orders, 1, order_idx + 1)\n", " for bus_volt_name_dpsim in bus_volt_name_dpsim_list:\n", - " plt.plot(ts_dpsim[order_idx][bus_volt_name_dpsim].time, ts_dpsim[order_idx][bus_volt_name_dpsim].phase().values/180*np.pi-ts_dpsim[order_idx]['BUS1.V'].phase().values/180*np.pi, label=bus_volt_name_dpsim +', '+order_names_list[order_idx]+' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", + " plt.plot(\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].time,\n", + " ts_dpsim[order_idx][bus_volt_name_dpsim].phase().values / 180 * np.pi\n", + " - ts_dpsim[order_idx][\"BUS1.V\"].phase().values / 180 * np.pi,\n", + " label=bus_volt_name_dpsim + \", \" + order_names_list[order_idx] + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", " for bus_angle_name_psat in bus_angle_name_psat_list:\n", - " plt.plot(ts_psat[order_idx][bus_angle_name_psat].time, ts_psat[order_idx][bus_angle_name_psat].values, label=bus_angle_name_psat +', '+order_names_list[order_idx]+' (psat)', linestyle='--', color='C'+str(bus_angle_name_psat_list.index(bus_angle_name_psat)))\n", - " \n", + " plt.plot(\n", + " ts_psat[order_idx][bus_angle_name_psat].time,\n", + " ts_psat[order_idx][bus_angle_name_psat].values,\n", + " label=bus_angle_name_psat + \", \" + order_names_list[order_idx] + \" (psat)\",\n", + " linestyle=\"--\",\n", + " color=\"C\" + str(bus_angle_name_psat_list.index(bus_angle_name_psat)),\n", + " )\n", + "\n", " plt.xlim(view_time_interval)\n", - " plt.xlabel('time (s)')\n", - " plt.ylabel('angle (rad)')\n", + " plt.xlabel(\"time (s)\")\n", + " plt.ylabel(\"angle (rad)\")\n", " plt.legend()" ] }, @@ -305,16 +473,31 @@ "outputs": [], "source": [ "for order_idx in range(num_orders):\n", - " plt.figure(figsize=(12,9))\n", - " #plt.subplot(num_orders,1,order_idx+1)\n", + " plt.figure(figsize=(12, 9))\n", + " # plt.subplot(num_orders,1,order_idx+1)\n", " for syngen_power_name_dpsim in syngen_power_name_dpsim_list:\n", - " plt.plot(ts_dpsim[order_idx][syngen_power_name_dpsim].time, ts_dpsim[order_idx][syngen_power_name_dpsim].values, label=syngen_power_name_dpsim+', '+order_names_list[order_idx]+' (dpsim)')\n", + " plt.plot(\n", + " ts_dpsim[order_idx][syngen_power_name_dpsim].time,\n", + " ts_dpsim[order_idx][syngen_power_name_dpsim].values,\n", + " label=syngen_power_name_dpsim\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (dpsim)\",\n", + " )\n", " for syngen_power_name_psat in syngen_power_name_psat_list:\n", - " plt.plot(ts_psat[order_idx][syngen_power_name_psat].time, ts_psat[order_idx][syngen_power_name_psat].values, label=syngen_power_name_psat+', '+order_names_list[order_idx]+' (psat)', linestyle='--')\n", - " \n", + " plt.plot(\n", + " ts_psat[order_idx][syngen_power_name_psat].time,\n", + " ts_psat[order_idx][syngen_power_name_psat].values,\n", + " label=syngen_power_name_psat\n", + " + \", \"\n", + " + order_names_list[order_idx]\n", + " + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "\n", " plt.xlim(view_time_interval)\n", - " plt.xlabel('time (s)')\n", - " plt.ylabel('torque (p.u)')\n", + " plt.xlabel(\"time (s)\")\n", + " plt.ylabel(\"torque (p.u)\")\n", " plt.legend()" ] }, @@ -333,19 +516,25 @@ "outputs": [], "source": [ "for order_idx in range(num_orders):\n", - " print('{} order:'.format(order_names_list[order_idx]))\n", - " \n", - " rmse_gen_1 = ts_psat[order_idx]['p_Syn_3'].rmse(ts_psat[order_idx]['p_Syn_3'],ts_dpsim[order_idx]['GEN1.Te'])\n", - " print('{}: {}'.format('GEN1',rmse_gen_1))\n", - " assert(rmse_gen_1 < 1e-2)\n", - " \n", - " rmse_gen_2 = ts_psat[order_idx]['p_Syn_1'].rmse(ts_psat[order_idx]['p_Syn_1'],ts_dpsim[order_idx]['GEN2.Te'])\n", - " print('{}: {}'.format('GEN2',rmse_gen_2))\n", - " assert(rmse_gen_2 < 1e-2)\n", - " \n", - " rmse_gen_3 = ts_psat[order_idx]['p_Syn_2'].rmse(ts_psat[order_idx]['p_Syn_2'],ts_dpsim[order_idx]['GEN3.Te'])\n", - " print('{}: {}'.format('GEN3',rmse_gen_3))\n", - " assert(rmse_gen_3 < 1e-2)" + " print(\"{} order:\".format(order_names_list[order_idx]))\n", + "\n", + " rmse_gen_1 = ts_psat[order_idx][\"p_Syn_3\"].rmse(\n", + " ts_psat[order_idx][\"p_Syn_3\"], ts_dpsim[order_idx][\"GEN1.Te\"]\n", + " )\n", + " print(\"{}: {}\".format(\"GEN1\", rmse_gen_1))\n", + " assert rmse_gen_1 < 1e-2\n", + "\n", + " rmse_gen_2 = ts_psat[order_idx][\"p_Syn_1\"].rmse(\n", + " ts_psat[order_idx][\"p_Syn_1\"], ts_dpsim[order_idx][\"GEN2.Te\"]\n", + " )\n", + " print(\"{}: {}\".format(\"GEN2\", rmse_gen_2))\n", + " assert rmse_gen_2 < 1e-2\n", + "\n", + " rmse_gen_3 = ts_psat[order_idx][\"p_Syn_2\"].rmse(\n", + " ts_psat[order_idx][\"p_Syn_2\"], ts_dpsim[order_idx][\"GEN3.Te\"]\n", + " )\n", + " print(\"{}: {}\".format(\"GEN3\", rmse_gen_3))\n", + " assert rmse_gen_3 < 1e-2" ] }, { diff --git a/examples/Notebooks/Grids/SP_WSCC9bus_SGTrStab_Switch_PSAT_Validation.ipynb b/examples/Notebooks/Grids/SP_WSCC9bus_SGTrStab_Switch_PSAT_Validation.ipynb index 16099921b3..2e0f27c648 100644 --- a/examples/Notebooks/Grids/SP_WSCC9bus_SGTrStab_Switch_PSAT_Validation.ipynb +++ b/examples/Notebooks/Grids/SP_WSCC9bus_SGTrStab_Switch_PSAT_Validation.ipynb @@ -16,18 +16,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX_Dyn/WSCC-09_RX'\n", - "filename = 'WSCC-09_RX_Dyn_Second'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX_Dyn/WSCC-09_RX\"\n", + "filename = \"WSCC-09_RX_Dyn_Second\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -51,7 +53,7 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'SP_WSCC-9bus_dyn_switch'" + "sim_name = \"SP_WSCC-9bus_dyn_switch\"" ] }, { @@ -67,32 +69,40 @@ "metadata": {}, "outputs": [], "source": [ - "dpsimpy.Logger.set_log_dir('logs/' + sim_name)\n", + "dpsimpy.Logger.set_log_dir(\"logs/\" + sim_name)\n", "reader = dpsimpy.CIMReader(sim_name, dpsimpy.LogLevel.debug, dpsimpy.LogLevel.debug)\n", - "system = reader.loadCIM(60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.TransientStability)\n", + "system = reader.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.SP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.TransientStability,\n", + ")\n", "\n", "# Extend topology with switch\n", - "sw = dpsimpy.sp.ph1.Switch('Fault', dpsimpy.LogLevel.info)\n", - "sw.set_parameters(1e12, 0.1*529)\n", - "sw.connect([dpsimpy.sp.SimNode.gnd, system.node('BUS7')])\n", + "sw = dpsimpy.sp.ph1.Switch(\"Fault\", dpsimpy.LogLevel.info)\n", + "sw.set_parameters(1e12, 0.1 * 529)\n", + "sw.connect([dpsimpy.sp.SimNode.gnd, system.node(\"BUS7\")])\n", "sw.open()\n", "system.add(sw)\n", "\n", "# Use omegNom for torque conversion in SG models for validation with PSAT\n", - "system.component('GEN1').set_model_flags(False)\n", - "system.component('GEN2').set_model_flags(False)\n", - "system.component('GEN3').set_model_flags(False)\n", + "system.component(\"GEN1\").set_model_flags(False)\n", + "system.component(\"GEN2\").set_model_flags(False)\n", + "system.component(\"GEN3\").set_model_flags(False)\n", "\n", "logger = dpsimpy.Logger(sim_name)\n", "\n", "for i in range(1, 10):\n", - " logger.log_attribute('v' + str(i), 'v', system.node('BUS' + str(i)))\n", + " logger.log_attribute(\"v\" + str(i), \"v\", system.node(\"BUS\" + str(i)))\n", "\n", "for i in range(1, 4):\n", - " logger.log_attribute('wr_' + str(i), 'w_r', system.component('GEN' + str(i)))\n", - " logger.log_attribute('delta_r_' + str(i), 'delta_r', system.component('GEN' + str(i)))\n", - " logger.log_attribute('P_elec_' + str(i), 'P_elec', system.component('GEN' + str(i)))\n", - " logger.log_attribute('P_mech_' + str(i), 'P_mech', system.component('GEN' + str(i)))\n", + " logger.log_attribute(\"wr_\" + str(i), \"w_r\", system.component(\"GEN\" + str(i)))\n", + " logger.log_attribute(\n", + " \"delta_r_\" + str(i), \"delta_r\", system.component(\"GEN\" + str(i))\n", + " )\n", + " logger.log_attribute(\"P_elec_\" + str(i), \"P_elec\", system.component(\"GEN\" + str(i)))\n", + " logger.log_attribute(\"P_mech_\" + str(i), \"P_mech\", system.component(\"GEN\" + str(i)))\n", "\n", "\n", "sim = dpsimpy.Simulation(sim_name, dpsimpy.LogLevel.debug)\n", @@ -107,7 +117,7 @@ "sim.add_event(sw_event_1)\n", "\n", "sim.add_logger(logger)\n", - "sim.run()\n" + "sim.run()" ] }, { @@ -123,9 +133,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/SP_WSCC-9bus_dyn_switch/'\n", - "logName = 'SP_WSCC-9bus_dyn_switch'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/SP_WSCC-9bus_dyn_switch/\"\n", + "logName = \"SP_WSCC-9bus_dyn_switch\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_dpsim = rt.read_timeseries_dpsim(logFilename)\n", @@ -145,11 +155,25 @@ "metadata": {}, "outputs": [], "source": [ - "nominal_voltages = {'v1': 16500, 'v2': 18000, 'v3': 13800, \n", - " 'v4': 230000, 'v5': 230000, 'v6': 230000, \n", - " 'v7': 230000, 'v8': 230000, 'v9': 230000} \n", + "nominal_voltages = {\n", + " \"v1\": 16500,\n", + " \"v2\": 18000,\n", + " \"v3\": 13800,\n", + " \"v4\": 230000,\n", + " \"v5\": 230000,\n", + " \"v6\": 230000,\n", + " \"v7\": 230000,\n", + " \"v8\": 230000,\n", + " \"v9\": 230000,\n", + "}\n", "for node, nom_voltage in nominal_voltages.items():\n", - " print(node + ': ' + str(phasors[node]['abs'].values[0] / nom_voltage) + '<' + str(phasors[node]['phase'].values[0]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasors[node][\"abs\"].values[0] / nom_voltage)\n", + " + \"<\"\n", + " + str(phasors[node][\"phase\"].values[0])\n", + " )" ] }, { @@ -166,21 +190,21 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(phasors['v1']['abs'].time, phasors['v1']['abs'].values, label='v1.abs')\n", - "plt.plot(phasors['v2']['abs'].time, phasors['v2']['abs'].values, label='v2.abs')\n", - "plt.plot(phasors['v3']['abs'].time, phasors['v3']['abs'].values, label='v3.abs')\n", + "plt.plot(phasors[\"v1\"][\"abs\"].time, phasors[\"v1\"][\"abs\"].values, label=\"v1.abs\")\n", + "plt.plot(phasors[\"v2\"][\"abs\"].time, phasors[\"v2\"][\"abs\"].values, label=\"v2.abs\")\n", + "plt.plot(phasors[\"v3\"][\"abs\"].time, phasors[\"v3\"][\"abs\"].values, label=\"v3.abs\")\n", "plt.legend()\n", - "plt.ylim([0,20000])\n", + "plt.ylim([0, 20000])\n", "\n", "plt.figure()\n", - "plt.plot(phasors['v4']['abs'].time, phasors['v4']['abs'].values, label='v4.abs')\n", - "plt.plot(phasors['v5']['abs'].time, phasors['v5']['abs'].values, label='v5.abs')\n", - "plt.plot(phasors['v6']['abs'].time, phasors['v6']['abs'].values, label='v6.abs')\n", - "plt.plot(phasors['v7']['abs'].time, phasors['v7']['abs'].values, label='v7.abs')\n", - "plt.plot(phasors['v8']['abs'].time, phasors['v8']['abs'].values, label='v8.abs')\n", - "plt.plot(phasors['v9']['abs'].time, phasors['v9']['abs'].values, label='v9.abs')\n", + "plt.plot(phasors[\"v4\"][\"abs\"].time, phasors[\"v4\"][\"abs\"].values, label=\"v4.abs\")\n", + "plt.plot(phasors[\"v5\"][\"abs\"].time, phasors[\"v5\"][\"abs\"].values, label=\"v5.abs\")\n", + "plt.plot(phasors[\"v6\"][\"abs\"].time, phasors[\"v6\"][\"abs\"].values, label=\"v6.abs\")\n", + "plt.plot(phasors[\"v7\"][\"abs\"].time, phasors[\"v7\"][\"abs\"].values, label=\"v7.abs\")\n", + "plt.plot(phasors[\"v8\"][\"abs\"].time, phasors[\"v8\"][\"abs\"].values, label=\"v8.abs\")\n", + "plt.plot(phasors[\"v9\"][\"abs\"].time, phasors[\"v9\"][\"abs\"].values, label=\"v9.abs\")\n", "plt.legend()\n", - "plt.ylim([0,240000])" + "plt.ylim([0, 240000])" ] }, { @@ -197,14 +221,14 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_dpsim['wr_1'].time, ts_dpsim['wr_1'].values, label='wr_1')\n", - "plt.plot(ts_dpsim['wr_2'].time, ts_dpsim['wr_2'].values, label='wr_2')\n", - "plt.plot(ts_dpsim['wr_3'].time, ts_dpsim['wr_3'].values, label='wr_3')\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('mechanical speed (rad/s)')\n", + "plt.plot(ts_dpsim[\"wr_1\"].time, ts_dpsim[\"wr_1\"].values, label=\"wr_1\")\n", + "plt.plot(ts_dpsim[\"wr_2\"].time, ts_dpsim[\"wr_2\"].values, label=\"wr_2\")\n", + "plt.plot(ts_dpsim[\"wr_3\"].time, ts_dpsim[\"wr_3\"].values, label=\"wr_3\")\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"mechanical speed (rad/s)\")\n", "plt.legend()\n", "plt.show()\n", - "#plt.savefig('wscc_9bus_fault_gen_speed.pdf')" + "# plt.savefig('wscc_9bus_fault_gen_speed.pdf')" ] }, { @@ -223,27 +247,53 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/WSCC-9bus/d_009_fault_dpsim_2nd_order.out'\n", - "local_file = 'reference-results/d_009_fault_dpsim_2nd_order.out'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/PSAT/WSCC-9bus/d_009_fault_dpsim_2nd_order.out\"\n", + "local_file = \"reference-results/d_009_fault_dpsim_2nd_order.out\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", - "syngen_power_name_dpsim_list = ['P_elec_1', 'P_elec_2', 'P_elec_3']\n", - "syngen_power_name_psat_list = ['p_Syn_1', 'p_Syn_2', 'p_Syn_3']\n", + "syngen_power_name_dpsim_list = [\"P_elec_1\", \"P_elec_2\", \"P_elec_3\"]\n", + "syngen_power_name_psat_list = [\"p_Syn_1\", \"p_Syn_2\", \"p_Syn_3\"]\n", "\n", - "syngen_omega_name_dpsim_list = ['wr_1', 'wr_2', 'wr_3']\n", - "syngen_omega_name_psat_list = ['omega_Syn_1', 'omega_Syn_2', 'omega_Syn_3']\n", + "syngen_omega_name_dpsim_list = [\"wr_1\", \"wr_2\", \"wr_3\"]\n", + "syngen_omega_name_psat_list = [\"omega_Syn_1\", \"omega_Syn_2\", \"omega_Syn_3\"]\n", "\n", - "syngen_delta_name_dpsim_list = ['delta_r_1', 'delta_r_2', 'delta_r_3']\n", - "syngen_delta_name_psat_list = ['delta_Syn_1', 'delta_Syn_2', 'delta_Syn_3']\n", + "syngen_delta_name_dpsim_list = [\"delta_r_1\", \"delta_r_2\", \"delta_r_3\"]\n", + "syngen_delta_name_psat_list = [\"delta_Syn_1\", \"delta_Syn_2\", \"delta_Syn_3\"]\n", "\n", - "bus_volt_name_dpsim_list = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8', 'v9']\n", - "bus_volt_name_psat_list = ['V_Bus 1', 'V_Bus 2', 'V_Bus 3', 'V_Bus 4', 'V_Bus 5', 'V_Bus 6', 'V_Bus 7', 'V_Bus 8', 'V_Bus 9']\n", - "bus_angle_name_psat_list = ['theta_Bus 1', 'theta_Bus 2', 'theta_Bus 3', 'theta_Bus 4', 'theta_Bus 5', 'theta_Bus 6', 'theta_Bus 7', 'theta_Bus 8', 'theta_Bus 9']\n", + "bus_volt_name_dpsim_list = [\"v1\", \"v2\", \"v3\", \"v4\", \"v5\", \"v6\", \"v7\", \"v8\", \"v9\"]\n", + "bus_volt_name_psat_list = [\n", + " \"V_Bus 1\",\n", + " \"V_Bus 2\",\n", + " \"V_Bus 3\",\n", + " \"V_Bus 4\",\n", + " \"V_Bus 5\",\n", + " \"V_Bus 6\",\n", + " \"V_Bus 7\",\n", + " \"V_Bus 8\",\n", + " \"V_Bus 9\",\n", + "]\n", + "bus_angle_name_psat_list = [\n", + " \"theta_Bus 1\",\n", + " \"theta_Bus 2\",\n", + " \"theta_Bus 3\",\n", + " \"theta_Bus 4\",\n", + " \"theta_Bus 5\",\n", + " \"theta_Bus 6\",\n", + " \"theta_Bus 7\",\n", + " \"theta_Bus 8\",\n", + " \"theta_Bus 9\",\n", + "]\n", "\n", - "timeseries_names_psat = syngen_power_name_psat_list+syngen_omega_name_psat_list+syngen_delta_name_psat_list+bus_volt_name_psat_list+bus_angle_name_psat_list\n", + "timeseries_names_psat = (\n", + " syngen_power_name_psat_list\n", + " + syngen_omega_name_psat_list\n", + " + syngen_delta_name_psat_list\n", + " + bus_volt_name_psat_list\n", + " + bus_angle_name_psat_list\n", + ")\n", "\n", "ts_psat = rt.read_timeseries_PSAT(local_file, timeseries_names_psat)" ] @@ -261,14 +311,25 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,9))\n", + "plt.figure(figsize=(12, 9))\n", "for syngen_omega_name_dpsim in syngen_omega_name_dpsim_list:\n", - " ts_dpsim[syngen_omega_name_dpsim].values = ts_dpsim[syngen_omega_name_dpsim].values/(2*np.pi*60)\n", - " plt.plot(ts_dpsim[syngen_omega_name_dpsim].time, ts_dpsim[syngen_omega_name_dpsim].values, label=syngen_omega_name_dpsim+' (dpsim)')\n", + " ts_dpsim[syngen_omega_name_dpsim].values = ts_dpsim[\n", + " syngen_omega_name_dpsim\n", + " ].values / (2 * np.pi * 60)\n", + " plt.plot(\n", + " ts_dpsim[syngen_omega_name_dpsim].time,\n", + " ts_dpsim[syngen_omega_name_dpsim].values,\n", + " label=syngen_omega_name_dpsim + \" (dpsim)\",\n", + " )\n", "for syngen_omega_name_psat in syngen_omega_name_psat_list:\n", - " plt.plot(ts_psat[syngen_omega_name_psat].time, ts_psat[syngen_omega_name_psat].values, label=syngen_omega_name_psat+' (psat)', linestyle='--')\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('mechanical speed (p.u)')\n", + " plt.plot(\n", + " ts_psat[syngen_omega_name_psat].time,\n", + " ts_psat[syngen_omega_name_psat].values,\n", + " label=syngen_omega_name_psat + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"mechanical speed (p.u)\")\n", "plt.legend()\n", "plt.show()" ] @@ -286,9 +347,27 @@ "metadata": {}, "outputs": [], "source": [ - "assert(ts_dpsim[syngen_omega_name_dpsim_list[0]].rmse(ts_dpsim[syngen_omega_name_dpsim_list[0]], ts_psat[syngen_omega_name_psat_list[2]]) < 2e-4)\n", - "assert(ts_dpsim[syngen_omega_name_dpsim_list[1]].rmse(ts_dpsim[syngen_omega_name_dpsim_list[1]], ts_psat[syngen_omega_name_psat_list[0]]) < 2e-4)\n", - "assert(ts_dpsim[syngen_omega_name_dpsim_list[2]].rmse(ts_dpsim[syngen_omega_name_dpsim_list[2]], ts_psat[syngen_omega_name_psat_list[1]]) < 2e-4)" + "assert (\n", + " ts_dpsim[syngen_omega_name_dpsim_list[0]].rmse(\n", + " ts_dpsim[syngen_omega_name_dpsim_list[0]],\n", + " ts_psat[syngen_omega_name_psat_list[2]],\n", + " )\n", + " < 2e-4\n", + ")\n", + "assert (\n", + " ts_dpsim[syngen_omega_name_dpsim_list[1]].rmse(\n", + " ts_dpsim[syngen_omega_name_dpsim_list[1]],\n", + " ts_psat[syngen_omega_name_psat_list[0]],\n", + " )\n", + " < 2e-4\n", + ")\n", + "assert (\n", + " ts_dpsim[syngen_omega_name_dpsim_list[2]].rmse(\n", + " ts_dpsim[syngen_omega_name_dpsim_list[2]],\n", + " ts_psat[syngen_omega_name_psat_list[1]],\n", + " )\n", + " < 2e-4\n", + ")" ] }, { @@ -304,13 +383,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,9))\n", + "plt.figure(figsize=(12, 9))\n", "for syngen_delta_name_dpsim in syngen_delta_name_dpsim_list:\n", - " plt.plot(ts_dpsim[syngen_delta_name_dpsim].time, ts_dpsim[syngen_delta_name_dpsim].values, label=syngen_delta_name_dpsim+' (dpsim)')\n", + " plt.plot(\n", + " ts_dpsim[syngen_delta_name_dpsim].time,\n", + " ts_dpsim[syngen_delta_name_dpsim].values,\n", + " label=syngen_delta_name_dpsim + \" (dpsim)\",\n", + " )\n", "for syngen_delta_name_psat in syngen_delta_name_psat_list:\n", - " plt.plot(ts_psat[syngen_delta_name_psat].time, ts_psat[syngen_delta_name_psat].values, label=syngen_delta_name_psat+' (psat)', linestyle='--')\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('rotor angle (deg)')\n", + " plt.plot(\n", + " ts_psat[syngen_delta_name_psat].time,\n", + " ts_psat[syngen_delta_name_psat].values,\n", + " label=syngen_delta_name_psat + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"rotor angle (deg)\")\n", "plt.legend()\n", "plt.show()" ] @@ -328,20 +416,46 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,9))\n", + "plt.figure(figsize=(12, 9))\n", "for bus_volt_name_dpsim in bus_volt_name_dpsim_list:\n", - " if bus_volt_name_dpsim == 'v1':\n", - " plt.plot(ts_dpsim[bus_volt_name_dpsim].time, ts_dpsim[bus_volt_name_dpsim].abs().values/16.5e3, label=bus_volt_name_dpsim + ' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", - " elif bus_volt_name_dpsim == 'v2':\n", - " plt.plot(ts_dpsim[bus_volt_name_dpsim].time, ts_dpsim[bus_volt_name_dpsim].abs().values/18e3, label=bus_volt_name_dpsim + ' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", - " elif bus_volt_name_dpsim == 'v3':\n", - " plt.plot(ts_dpsim[bus_volt_name_dpsim].time, ts_dpsim[bus_volt_name_dpsim].abs().values/13.8e3, label=bus_volt_name_dpsim + ' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", + " if bus_volt_name_dpsim == \"v1\":\n", + " plt.plot(\n", + " ts_dpsim[bus_volt_name_dpsim].time,\n", + " ts_dpsim[bus_volt_name_dpsim].abs().values / 16.5e3,\n", + " label=bus_volt_name_dpsim + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", + " elif bus_volt_name_dpsim == \"v2\":\n", + " plt.plot(\n", + " ts_dpsim[bus_volt_name_dpsim].time,\n", + " ts_dpsim[bus_volt_name_dpsim].abs().values / 18e3,\n", + " label=bus_volt_name_dpsim + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", + " elif bus_volt_name_dpsim == \"v3\":\n", + " plt.plot(\n", + " ts_dpsim[bus_volt_name_dpsim].time,\n", + " ts_dpsim[bus_volt_name_dpsim].abs().values / 13.8e3,\n", + " label=bus_volt_name_dpsim + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", " else:\n", - " plt.plot(ts_dpsim[bus_volt_name_dpsim].time, ts_dpsim[bus_volt_name_dpsim].abs().values/230e3, label=bus_volt_name_dpsim + ' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", + " plt.plot(\n", + " ts_dpsim[bus_volt_name_dpsim].time,\n", + " ts_dpsim[bus_volt_name_dpsim].abs().values / 230e3,\n", + " label=bus_volt_name_dpsim + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", "for bus_volt_name_psat in bus_volt_name_psat_list:\n", - " plt.plot(ts_psat[bus_volt_name_psat].time, ts_psat[bus_volt_name_psat].values, label=bus_volt_name_psat + ' (psat)', linestyle='--', color='C'+str(bus_volt_name_psat_list.index(bus_volt_name_psat)))\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (p.u.)')\n", + " plt.plot(\n", + " ts_psat[bus_volt_name_psat].time,\n", + " ts_psat[bus_volt_name_psat].values,\n", + " label=bus_volt_name_psat + \" (psat)\",\n", + " linestyle=\"--\",\n", + " color=\"C\" + str(bus_volt_name_psat_list.index(bus_volt_name_psat)),\n", + " )\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (p.u.)\")\n", "plt.legend()\n", "plt.show()" ] @@ -359,13 +473,24 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,9))\n", + "plt.figure(figsize=(12, 9))\n", "for bus_volt_name_dpsim in bus_volt_name_dpsim_list:\n", - " plt.plot(ts_dpsim[bus_volt_name_dpsim].time, ts_dpsim[bus_volt_name_dpsim].phase().values/180*np.pi, label=bus_volt_name_dpsim + ' (dpsim)', color='C'+str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)))\n", + " plt.plot(\n", + " ts_dpsim[bus_volt_name_dpsim].time,\n", + " ts_dpsim[bus_volt_name_dpsim].phase().values / 180 * np.pi,\n", + " label=bus_volt_name_dpsim + \" (dpsim)\",\n", + " color=\"C\" + str(bus_volt_name_dpsim_list.index(bus_volt_name_dpsim)),\n", + " )\n", "for bus_angle_name_psat in bus_angle_name_psat_list:\n", - " plt.plot(ts_psat[bus_angle_name_psat].time, ts_psat[bus_angle_name_psat].values, label=bus_angle_name_psat + ' (psat)', linestyle='--', color='C'+str(bus_angle_name_psat_list.index(bus_angle_name_psat)))\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('angle (rad)')\n", + " plt.plot(\n", + " ts_psat[bus_angle_name_psat].time,\n", + " ts_psat[bus_angle_name_psat].values,\n", + " label=bus_angle_name_psat + \" (psat)\",\n", + " linestyle=\"--\",\n", + " color=\"C\" + str(bus_angle_name_psat_list.index(bus_angle_name_psat)),\n", + " )\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"angle (rad)\")\n", "plt.legend()\n", "plt.show()" ] @@ -383,13 +508,22 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12,9))\n", + "plt.figure(figsize=(12, 9))\n", "for syngen_power_name_dpsim in syngen_power_name_dpsim_list:\n", - " plt.plot(ts_dpsim[syngen_power_name_dpsim].time, ts_dpsim[syngen_power_name_dpsim].values/100e6, label=syngen_power_name_dpsim+' (dpsim)')\n", + " plt.plot(\n", + " ts_dpsim[syngen_power_name_dpsim].time,\n", + " ts_dpsim[syngen_power_name_dpsim].values / 100e6,\n", + " label=syngen_power_name_dpsim + \" (dpsim)\",\n", + " )\n", "for syngen_power_name_psat in syngen_power_name_psat_list:\n", - " plt.plot(ts_psat[syngen_power_name_psat].time, ts_psat[syngen_power_name_psat].values, label=syngen_power_name_psat+' (psat)', linestyle='--')\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('power (W)')\n", + " plt.plot(\n", + " ts_psat[syngen_power_name_psat].time,\n", + " ts_psat[syngen_power_name_psat].values,\n", + " label=syngen_power_name_psat + \" (psat)\",\n", + " linestyle=\"--\",\n", + " )\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"power (W)\")\n", "plt.legend()\n", "plt.show()" ] diff --git a/examples/Notebooks/Grids/case14.ipynb b/examples/Notebooks/Grids/case14.ipynb index 092d845a38..93efbdb5ef 100644 --- a/examples/Notebooks/Grids/case14.ipynb +++ b/examples/Notebooks/Grids/case14.ipynb @@ -21,9 +21,10 @@ "outputs": [], "source": [ "import requests\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case14.xml'\n", - "filename = 'case14.xml'\n", - "with open(filename, 'wb') as out_file:\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case14.xml\"\n", + "filename = \"case14.xml\"\n", + "with open(filename, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", @@ -46,9 +47,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'case14'\n", + "name = \"case14\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "system" ] }, @@ -66,7 +69,7 @@ "logger = dpsimpy.Logger(name)\n", "sim.add_logger(logger)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node);" + " logger.log_attribute(node.name() + \".V\", \"v\", node);" ] }, { @@ -91,7 +94,7 @@ "metadata": {}, "outputs": [], "source": [ - "dpsim_result_file = 'logs/' + name + '.csv'\n", + "dpsim_result_file = \"logs/\" + name + \".csv\"\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -101,8 +104,8 @@ "metadata": {}, "outputs": [], "source": [ - "for k,v in ts_dpsim.items():\n", - " print(v.name + ':' + str(v.values[0]))" + "for k, v in ts_dpsim.items():\n", + " print(v.name + \":\" + str(v.values[0]))" ] } ], diff --git a/examples/Notebooks/Grids/case145.ipynb b/examples/Notebooks/Grids/case145.ipynb index 74418ce8a1..5508b1b9f7 100644 --- a/examples/Notebooks/Grids/case145.ipynb +++ b/examples/Notebooks/Grids/case145.ipynb @@ -21,9 +21,10 @@ "outputs": [], "source": [ "import requests\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case145.xml'\n", - "filename = 'case145.xml'\n", - "with open(filename, 'wb') as out_file:\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case145.xml\"\n", + "filename = \"case145.xml\"\n", + "with open(filename, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", @@ -46,9 +47,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'case145'\n", + "name = \"case145\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "system" ] }, @@ -66,7 +69,7 @@ "logger = dpsimpy.Logger(name)\n", "sim.add_logger(logger)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node);" + " logger.log_attribute(node.name() + \".V\", \"v\", node);" ] }, { @@ -91,7 +94,7 @@ "metadata": {}, "outputs": [], "source": [ - "dpsim_result_file = 'logs/' + name + '.csv'\n", + "dpsim_result_file = \"logs/\" + name + \".csv\"\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -101,8 +104,8 @@ "metadata": {}, "outputs": [], "source": [ - "for k,v in ts_dpsim.items():\n", - " print(v.name + ':' + str(v.values[0]))" + "for k, v in ts_dpsim.items():\n", + " print(v.name + \":\" + str(v.values[0]))" ] }, { diff --git a/examples/Notebooks/Grids/case300.ipynb b/examples/Notebooks/Grids/case300.ipynb index cc804f3420..015fe65d1f 100644 --- a/examples/Notebooks/Grids/case300.ipynb +++ b/examples/Notebooks/Grids/case300.ipynb @@ -21,9 +21,10 @@ "outputs": [], "source": [ "import requests\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case300.xml'\n", - "filename = 'case300.xml'\n", - "with open(filename, 'wb') as out_file:\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case300.xml\"\n", + "filename = \"case300.xml\"\n", + "with open(filename, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", @@ -46,9 +47,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'case300'\n", + "name = \"case300\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "system" ] }, @@ -66,7 +69,7 @@ "logger = dpsimpy.Logger(name)\n", "sim.add_logger(logger)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node);" + " logger.log_attribute(node.name() + \".V\", \"v\", node);" ] }, { @@ -91,7 +94,7 @@ "metadata": {}, "outputs": [], "source": [ - "dpsim_result_file = 'logs/' + name + '.csv'\n", + "dpsim_result_file = \"logs/\" + name + \".csv\"\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -101,8 +104,8 @@ "metadata": {}, "outputs": [], "source": [ - "for k,v in ts_dpsim.items():\n", - " print(v.name + ':' + str(v.values[0]))" + "for k, v in ts_dpsim.items():\n", + " print(v.name + \":\" + str(v.values[0]))" ] }, { diff --git a/examples/Notebooks/Grids/case9.ipynb b/examples/Notebooks/Grids/case9.ipynb index 1c35295f4a..fb9f023efd 100644 --- a/examples/Notebooks/Grids/case9.ipynb +++ b/examples/Notebooks/Grids/case9.ipynb @@ -21,9 +21,10 @@ "outputs": [], "source": [ "import requests\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case9.xml'\n", - "filename = 'case9.xml'\n", - "with open(filename, 'wb') as out_file:\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/Matpower_cases/case9.xml\"\n", + "filename = \"case9.xml\"\n", + "with open(filename, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", @@ -46,9 +47,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'case9'\n", + "name = \"case9\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", "system" ] }, @@ -66,7 +69,7 @@ "logger = dpsimpy.Logger(name)\n", "sim.add_logger(logger)\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node);" + " logger.log_attribute(node.name() + \".V\", \"v\", node);" ] }, { @@ -91,7 +94,7 @@ "metadata": {}, "outputs": [], "source": [ - "dpsim_result_file = 'logs/' + name + '.csv'\n", + "dpsim_result_file = \"logs/\" + name + \".csv\"\n", "ts_dpsim = read_timeseries_csv(dpsim_result_file)" ] }, @@ -101,8 +104,8 @@ "metadata": {}, "outputs": [], "source": [ - "for k,v in ts_dpsim.items():\n", - " print(v.name + ':' + str(v.values[0]))" + "for k, v in ts_dpsim.items():\n", + " print(v.name + \":\" + str(v.values[0]))" ] } ], diff --git a/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_SparseLU_KLU_fault_comparison.ipynb b/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_SparseLU_KLU_fault_comparison.ipynb index 61092ce9da..ca79ef4616 100644 --- a/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_SparseLU_KLU_fault_comparison.ipynb +++ b/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_SparseLU_KLU_fault_comparison.ipynb @@ -58,20 +58,22 @@ "\n", "log_level = dpsimpy.LogLevel.trace\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "filename = 'WSCC-09_Dyn_Fourth'\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", - "download_grid_data(filename+'_DI.xml', url+'_DI.xml')\n", - " \n", - "files = glob.glob(filename+'_*.xml')" + "filename = \"WSCC-09_Dyn_Fourth\"\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "download_grid_data(filename + \"_DI.xml\", url + \"_DI.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")" ] }, { @@ -91,19 +93,21 @@ "source": [ "sim_name_pf = example_name + \"_PF\"\n", "\n", - "dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, log_level, log_level)\n", "\n", - "system_pf = reader.loadCIM(60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", - "system_pf.component('GEN1').modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", + "system_pf = reader.loadCIM(\n", + " 60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", + "system_pf.component(\"GEN1\").modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", " logger_pf.log_attribute(node.name() + \".V\", node.attr(\"v\"))\n", - " \n", + "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, log_level)\n", "sim_pf.set_system(system_pf)\n", "sim_pf.set_time_step(final_time)\n", - "sim_pf.set_final_time(2*final_time)\n", + "sim_pf.set_final_time(2 * final_time)\n", "sim_pf.set_domain(dpsimpy.Domain.SP)\n", "sim_pf.set_solver(dpsimpy.Solver.NRP)\n", "sim_pf.set_solver_component_behaviour(dpsimpy.SolverBehaviour.Initialization)\n", @@ -127,16 +131,38 @@ "metadata": {}, "outputs": [], "source": [ - "def run_simulation(sim_name, implementation, model_syngens_as_norton, config = dpsimpy.DirectLinearSolverConfiguration()):\n", - " \n", - " dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name)\n", + "def run_simulation(\n", + " sim_name,\n", + " implementation,\n", + " model_syngens_as_norton,\n", + " config=dpsimpy.DirectLinearSolverConfiguration(),\n", + "):\n", + " dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name)\n", " reader2 = dpsimpy.CIMReader(sim_name, log_level, log_level)\n", " if sg_type == \"3\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG3OrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG3OrderVBR,\n", + " )\n", " elif sg_type == \"4\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG4OrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG4OrderVBR,\n", + " )\n", " elif sg_type == \"6b\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG6bOrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG6bOrderVBR,\n", + " )\n", " else:\n", " raise Exception(\"Unsupported reduced-order SG type!\")\n", "\n", @@ -144,18 +170,18 @@ "\n", " if with_fault == True:\n", " n1_dp = dpsimpy.dp.SimNode(fault_bus_name, dpsimpy.PhaseType.Single)\n", - " fault_dp.set_parameters(1e12, 0.02*529)\n", + " fault_dp.set_parameters(1e12, 0.02 * 529)\n", " fault_dp.connect([dpsimpy.dp.SimNode.gnd, n1_dp])\n", " fault_dp.open()\n", " sys.add(fault_dp)\n", "\n", " sys.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", - " \n", + "\n", " for comp in sys.components:\n", - " if comp.__class__ == dpsimpy.dp.ph1.SynchronGenerator4OrderVBR:\n", - " gen_pf = system_pf.component(comp.name())\n", - " comp.get_terminal(index=0).set_power(- gen_pf.get_apparent_power())\n", - " comp.set_model_as_norton_source(model_syngens_as_norton)\n", + " if comp.__class__ == dpsimpy.dp.ph1.SynchronGenerator4OrderVBR:\n", + " gen_pf = system_pf.component(comp.name())\n", + " comp.get_terminal(index=0).set_power(-gen_pf.get_apparent_power())\n", + " comp.set_model_as_norton_source(model_syngens_as_norton)\n", "\n", " logger = dpsimpy.Logger(sim_name)\n", " for node in sys.nodes:\n", @@ -218,11 +244,17 @@ "outputs": [], "source": [ "%%capture\n", - "sim_name_lu_thevenin = example_name+'_SparseLU_thevenin'\n", - "run_simulation(sim_name_lu_thevenin,dpsimpy.DirectLinearSolverImpl.SparseLU,False)\n", - "ts_dpsim_sparse_thevenin = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_lu_thevenin+\".csv\")\n", - "ts_dpsim_sparse_thevenin_rhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_lu_thevenin+\"_RightVector.csv\")\n", - "ts_dpsim_sparse_thevenin_lhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_lu_thevenin+\"_LeftVector.csv\")" + "sim_name_lu_thevenin = example_name + \"_SparseLU_thevenin\"\n", + "run_simulation(sim_name_lu_thevenin, dpsimpy.DirectLinearSolverImpl.SparseLU, False)\n", + "ts_dpsim_sparse_thevenin = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_lu_thevenin + \".csv\"\n", + ")\n", + "ts_dpsim_sparse_thevenin_rhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_lu_thevenin + \"_RightVector.csv\"\n", + ")\n", + "ts_dpsim_sparse_thevenin_lhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_lu_thevenin + \"_LeftVector.csv\"\n", + ")" ] }, { @@ -245,11 +277,17 @@ "outputs": [], "source": [ "%%capture\n", - "sim_name_lu_norton = example_name+'_SparseLU_norton'\n", - "run_simulation(sim_name_lu_norton,dpsimpy.DirectLinearSolverImpl.SparseLU,True)\n", - "ts_dpsim_sparse_norton = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_lu_norton+\".csv\")\n", - "ts_dpsim_sparse_norton_rhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_lu_norton+\"_RightVector.csv\")\n", - "ts_dpsim_sparse_norton_lhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_lu_norton+\"_LeftVector.csv\")" + "sim_name_lu_norton = example_name + \"_SparseLU_norton\"\n", + "run_simulation(sim_name_lu_norton, dpsimpy.DirectLinearSolverImpl.SparseLU, True)\n", + "ts_dpsim_sparse_norton = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_lu_norton + \".csv\"\n", + ")\n", + "ts_dpsim_sparse_norton_rhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_lu_norton + \"_RightVector.csv\"\n", + ")\n", + "ts_dpsim_sparse_norton_lhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_lu_norton + \"_LeftVector.csv\"\n", + ")" ] }, { @@ -270,11 +308,17 @@ "outputs": [], "source": [ "%%capture\n", - "sim_name_klu_pf_thevenin = example_name+'_KLU_pf_thevenin'\n", - "run_simulation(sim_name_klu_pf_thevenin,dpsimpy.DirectLinearSolverImpl.KLU,False)\n", - "ts_dpsim_klu_pf_thevenin = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_pf_thevenin+\".csv\")\n", - "ts_dpsim_klu_pf_thevenin_rhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_pf_thevenin+\"_RightVector.csv\")\n", - "ts_dpsim_klu_pf_thevenin_lhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_pf_thevenin+\"_LeftVector.csv\")" + "sim_name_klu_pf_thevenin = example_name + \"_KLU_pf_thevenin\"\n", + "run_simulation(sim_name_klu_pf_thevenin, dpsimpy.DirectLinearSolverImpl.KLU, False)\n", + "ts_dpsim_klu_pf_thevenin = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_pf_thevenin + \".csv\"\n", + ")\n", + "ts_dpsim_klu_pf_thevenin_rhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_pf_thevenin + \"_RightVector.csv\"\n", + ")\n", + "ts_dpsim_klu_pf_thevenin_lhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_pf_thevenin + \"_LeftVector.csv\"\n", + ")" ] }, { @@ -293,11 +337,17 @@ "outputs": [], "source": [ "%%capture\n", - "sim_name_klu_pf_norton = example_name+'_KLU_pf_norton'\n", - "run_simulation(sim_name_klu_pf_norton,dpsimpy.DirectLinearSolverImpl.KLU,True)\n", - "ts_dpsim_klu_pf_norton = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_pf_norton+\".csv\")\n", - "ts_dpsim_klu_pf_norton_rhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_pf_norton+\"_RightVector.csv\")\n", - "ts_dpsim_klu_pf_norton_lhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_pf_norton+\"_LeftVector.csv\")" + "sim_name_klu_pf_norton = example_name + \"_KLU_pf_norton\"\n", + "run_simulation(sim_name_klu_pf_norton, dpsimpy.DirectLinearSolverImpl.KLU, True)\n", + "ts_dpsim_klu_pf_norton = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_pf_norton + \".csv\"\n", + ")\n", + "ts_dpsim_klu_pf_norton_rhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_pf_norton + \"_RightVector.csv\"\n", + ")\n", + "ts_dpsim_klu_pf_norton_lhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_pf_norton + \"_LeftVector.csv\"\n", + ")" ] }, { @@ -323,12 +373,22 @@ "source": [ "%%capture\n", "config = dpsimpy.DirectLinearSolverConfiguration()\n", - "config.set_partial_refactorization_method(dpsimpy.partial_refactorization_method.no_partial_refactorization)\n", - "sim_name_klu_cf_thevenin = example_name+'_KLU_cf_thevenin'\n", - "run_simulation(sim_name_klu_cf_thevenin, dpsimpy.DirectLinearSolverImpl.KLU, False, config)\n", - "ts_dpsim_klu_cf_thevenin = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_cf_thevenin+\".csv\")\n", - "ts_dpsim_klu_cf_thevenin_rhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_cf_thevenin+\"_RightVector.csv\")\n", - "ts_dpsim_klu_cf_thevenin_lhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_cf_thevenin+\"_LeftVector.csv\")" + "config.set_partial_refactorization_method(\n", + " dpsimpy.partial_refactorization_method.no_partial_refactorization\n", + ")\n", + "sim_name_klu_cf_thevenin = example_name + \"_KLU_cf_thevenin\"\n", + "run_simulation(\n", + " sim_name_klu_cf_thevenin, dpsimpy.DirectLinearSolverImpl.KLU, False, config\n", + ")\n", + "ts_dpsim_klu_cf_thevenin = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_cf_thevenin + \".csv\"\n", + ")\n", + "ts_dpsim_klu_cf_thevenin_rhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_cf_thevenin + \"_RightVector.csv\"\n", + ")\n", + "ts_dpsim_klu_cf_thevenin_lhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_cf_thevenin + \"_LeftVector.csv\"\n", + ")" ] }, { @@ -352,12 +412,20 @@ "source": [ "%%capture\n", "config = dpsimpy.DirectLinearSolverConfiguration()\n", - "config.set_partial_refactorization_method(dpsimpy.partial_refactorization_method.no_partial_refactorization)\n", - "sim_name_klu_cf_norton = example_name+'_KLU_cf_norton'\n", + "config.set_partial_refactorization_method(\n", + " dpsimpy.partial_refactorization_method.no_partial_refactorization\n", + ")\n", + "sim_name_klu_cf_norton = example_name + \"_KLU_cf_norton\"\n", "run_simulation(sim_name_klu_cf_norton, dpsimpy.DirectLinearSolverImpl.KLU, True, config)\n", - "ts_dpsim_klu_cf_norton = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_cf_norton+\".csv\")\n", - "ts_dpsim_klu_cf_norton_rhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_cf_norton+\"_RightVector.csv\")\n", - "ts_dpsim_klu_cf_norton_lhs = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name_klu_cf_norton+\"_LeftVector.csv\")" + "ts_dpsim_klu_cf_norton = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_cf_norton + \".csv\"\n", + ")\n", + "ts_dpsim_klu_cf_norton_rhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_cf_norton + \"_RightVector.csv\"\n", + ")\n", + "ts_dpsim_klu_cf_norton_lhs = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name_klu_cf_norton + \"_LeftVector.csv\"\n", + ")" ] }, { @@ -401,8 +469,11 @@ "# Constants\n", "close_to_zero_tolerance = 1e-12\n", "\n", + "\n", "# Helper function relative error (relative to vector1)\n", - "def relative_error(vector1: np.ndarray, vector2: np.ndarray) -> (np.ndarray, float, int):\n", + "def relative_error(\n", + " vector1: np.ndarray, vector2: np.ndarray\n", + ") -> (np.ndarray, float, int):\n", " N = len(vector1)\n", " rel_error = np.zeros(N, dtype=float)\n", " for i in range(0, N - 1):\n", @@ -415,47 +486,71 @@ " # [RV, LV]\n", " maxerror = [0.0, 0.0]\n", " maxerror_timestamp = [0, 0]\n", - " maxerror_entry = ['', '']\n", - "\n", + " maxerror_entry = [\"\", \"\"]\n", "\n", " # Relative error in right vector\n", - " print('Maximum relative error in right vector for each entry (when > 0)')\n", + " print(\"Maximum relative error in right vector for each entry (when > 0)\")\n", " for entry in sparse_r_vec:\n", " sparse_values = sparse_r_vec[entry].values\n", " klu_values = klu_r_vec[entry].values\n", "\n", - " relative_error_klu_sparse, max_error_rv, max_error_rv_timestamp = relative_error(sparse_values, klu_values)\n", + " (\n", + " relative_error_klu_sparse,\n", + " max_error_rv,\n", + " max_error_rv_timestamp,\n", + " ) = relative_error(sparse_values, klu_values)\n", " if max_error_rv > maxerror[0]:\n", " maxerror[0] = max_error_rv\n", " maxerror_timestamp[0] = max_error_rv_timestamp\n", " maxerror_entry[0] = entry\n", " if max_error_rv > close_to_zero_tolerance:\n", - " print('Entry {}: {:.3e} at {}s'.format(entry, max_error_rv, max_error_rv_timestamp / 1000.0))\n", - " print('Maximum relative error in right vector: {} {:.3e} {}s'.format(maxerror_entry[0], maxerror[0], maxerror_timestamp[0] / 1000.0))\n", - "\n", + " print(\n", + " \"Entry {}: {:.3e} at {}s\".format(\n", + " entry, max_error_rv, max_error_rv_timestamp / 1000.0\n", + " )\n", + " )\n", + " print(\n", + " \"Maximum relative error in right vector: {} {:.3e} {}s\".format(\n", + " maxerror_entry[0], maxerror[0], maxerror_timestamp[0] / 1000.0\n", + " )\n", + " )\n", "\n", " # Relative error in left vector\n", - " print('\\nMaximum relative error in left vector for each entry (when > 0)')\n", + " print(\"\\nMaximum relative error in left vector for each entry (when > 0)\")\n", " for entry in sparse_l_vec:\n", " sparse_values = sparse_l_vec[entry].values\n", " klu_values = klu_l_vec[entry].values\n", "\n", - " relative_error_klu_sparse, max_error_lv, max_error_lv_timestamp = relative_error(sparse_values, klu_values)\n", + " (\n", + " relative_error_klu_sparse,\n", + " max_error_lv,\n", + " max_error_lv_timestamp,\n", + " ) = relative_error(sparse_values, klu_values)\n", " if max_error_lv > maxerror[1]:\n", " maxerror[1] = max_error_lv\n", " maxerror_timestamp[1] = max_error_lv_timestamp\n", " maxerror_entry[1] = entry\n", " if max_error_lv > close_to_zero_tolerance:\n", - " print('Entry {}: {:.3e} at {}s'.format(entry, max_error_lv, max_error_lv_timestamp / 1000.0))\n", - " print('Maximum relative error in left vector: {} {:.3e} {}s'.format(maxerror_entry[1], maxerror[1], maxerror_timestamp[1] / 1000.0))\n", - "\n", - " _rvlv = ['right', 'left']\n", - " print('\\nMaximum relative error in all values: {:.3e} at {}s at entry {} in {} vector'.format(\n", - " max(maxerror),\n", - " maxerror_timestamp[np.argmax(maxerror)] / 1000.0,\n", - " maxerror_entry[np.argmax(maxerror)],\n", - " _rvlv[np.argmax(maxerror)])\n", - " )\n", + " print(\n", + " \"Entry {}: {:.3e} at {}s\".format(\n", + " entry, max_error_lv, max_error_lv_timestamp / 1000.0\n", + " )\n", + " )\n", + " print(\n", + " \"Maximum relative error in left vector: {} {:.3e} {}s\".format(\n", + " maxerror_entry[1], maxerror[1], maxerror_timestamp[1] / 1000.0\n", + " )\n", + " )\n", + "\n", + " _rvlv = [\"right\", \"left\"]\n", + " print(\n", + " \"\\nMaximum relative error in all values: {:.3e} at {}s at entry {} in {} vector\".format(\n", + " max(maxerror),\n", + " maxerror_timestamp[np.argmax(maxerror)] / 1000.0,\n", + " maxerror_entry[np.argmax(maxerror)],\n", + " _rvlv[np.argmax(maxerror)],\n", + " )\n", + " )\n", " return max(maxerror)" ] }, @@ -488,11 +583,13 @@ "source": [ "# KLU partial refactorization / SparseLU, thevenin equivalent\n", "max_error = evaluation_func(\n", - " ts_dpsim_sparse_thevenin_rhs, ts_dpsim_sparse_thevenin_lhs,\n", - " ts_dpsim_klu_pf_thevenin_rhs, ts_dpsim_klu_pf_thevenin_lhs\n", + " ts_dpsim_sparse_thevenin_rhs,\n", + " ts_dpsim_sparse_thevenin_lhs,\n", + " ts_dpsim_klu_pf_thevenin_rhs,\n", + " ts_dpsim_klu_pf_thevenin_lhs,\n", ")\n", "\n", - "assert(max_error < max_rel_error)" + "assert max_error < max_rel_error" ] }, { @@ -504,11 +601,13 @@ "source": [ "# KLU partial refactorization / SparseLU, norton equivalent\n", "max_error = evaluation_func(\n", - " ts_dpsim_sparse_norton_rhs, ts_dpsim_sparse_norton_lhs,\n", - " ts_dpsim_klu_pf_norton_rhs, ts_dpsim_klu_pf_norton_lhs\n", + " ts_dpsim_sparse_norton_rhs,\n", + " ts_dpsim_sparse_norton_lhs,\n", + " ts_dpsim_klu_pf_norton_rhs,\n", + " ts_dpsim_klu_pf_norton_lhs,\n", ")\n", "\n", - "assert(max_error < max_rel_error)" + "assert max_error < max_rel_error" ] }, { @@ -520,11 +619,13 @@ "source": [ "# KLU complete refactorization / SparseLU, thevenin equivalent\n", "max_error = evaluation_func(\n", - " ts_dpsim_sparse_thevenin_rhs, ts_dpsim_sparse_thevenin_lhs,\n", - " ts_dpsim_klu_cf_thevenin_rhs, ts_dpsim_klu_cf_thevenin_lhs\n", + " ts_dpsim_sparse_thevenin_rhs,\n", + " ts_dpsim_sparse_thevenin_lhs,\n", + " ts_dpsim_klu_cf_thevenin_rhs,\n", + " ts_dpsim_klu_cf_thevenin_lhs,\n", ")\n", "\n", - "assert(max_error < max_rel_error)" + "assert max_error < max_rel_error" ] }, { @@ -536,11 +637,13 @@ "source": [ "# KLU complete refactorization / SparseLU, norton equivalent\n", "max_error = evaluation_func(\n", - " ts_dpsim_sparse_norton_rhs, ts_dpsim_sparse_norton_lhs,\n", - " ts_dpsim_klu_cf_norton_rhs, ts_dpsim_klu_cf_norton_lhs\n", + " ts_dpsim_sparse_norton_rhs,\n", + " ts_dpsim_sparse_norton_lhs,\n", + " ts_dpsim_klu_cf_norton_rhs,\n", + " ts_dpsim_klu_cf_norton_lhs,\n", ")\n", "\n", - "assert(max_error < max_rel_error)" + "assert max_error < max_rel_error" ] }, { @@ -552,11 +655,13 @@ "source": [ "# KLU complete refactorization / KLU partial refactorization, thevenin equivalent\n", "max_error = evaluation_func(\n", - " ts_dpsim_klu_pf_thevenin_rhs, ts_dpsim_klu_pf_thevenin_lhs,\n", - " ts_dpsim_klu_cf_thevenin_rhs, ts_dpsim_klu_cf_thevenin_lhs\n", + " ts_dpsim_klu_pf_thevenin_rhs,\n", + " ts_dpsim_klu_pf_thevenin_lhs,\n", + " ts_dpsim_klu_cf_thevenin_rhs,\n", + " ts_dpsim_klu_cf_thevenin_lhs,\n", ")\n", "\n", - "assert(max_error < max_rel_error)" + "assert max_error < max_rel_error" ] }, { @@ -568,11 +673,13 @@ "source": [ "# KLU complete refactorization / KLU partial refactorization, norton equivalent\n", "max_error = evaluation_func(\n", - " ts_dpsim_klu_pf_norton_rhs, ts_dpsim_klu_pf_norton_lhs,\n", - " ts_dpsim_klu_cf_norton_rhs, ts_dpsim_klu_cf_norton_lhs\n", + " ts_dpsim_klu_pf_norton_rhs,\n", + " ts_dpsim_klu_pf_norton_lhs,\n", + " ts_dpsim_klu_cf_norton_rhs,\n", + " ts_dpsim_klu_cf_norton_lhs,\n", ")\n", "\n", - "assert(max_error < max_rel_error)" + "assert max_error < max_rel_error" ] } ], diff --git a/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_KLU_using_different_settings.ipynb b/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_KLU_using_different_settings.ipynb index 466439e420..0106c50191 100644 --- a/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_KLU_using_different_settings.ipynb +++ b/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_KLU_using_different_settings.ipynb @@ -44,34 +44,38 @@ "else:\n", " log_down_sampling = 1.0\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "filename = 'WSCC-09_Dyn_Fourth'\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", - "download_grid_data(filename+'_DI.xml', url+'_DI.xml')\n", - " \n", - "files = glob.glob(filename+'_*.xml')\n", + "filename = \"WSCC-09_Dyn_Fourth\"\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "download_grid_data(filename + \"_DI.xml\", url + \"_DI.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "\n", - "dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name_pf)\n", + "dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, log_level, log_level)\n", "\n", - "system_pf = reader.loadCIM(60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", - "system_pf.component('GEN1').modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", + "system_pf = reader.loadCIM(\n", + " 60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", + "system_pf.component(\"GEN1\").modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", " logger_pf.log_attribute(node.name() + \".V\", node.attr(\"v\"))\n", - " \n", + "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, log_level)\n", "sim_pf.set_system(system_pf)\n", "sim_pf.set_time_step(final_time)\n", - "sim_pf.set_final_time(2*final_time)\n", + "sim_pf.set_final_time(2 * final_time)\n", "sim_pf.set_domain(dpsimpy.Domain.SP)\n", "sim_pf.set_solver(dpsimpy.Solver.NRP)\n", "sim_pf.set_solver_component_behaviour(dpsimpy.SolverBehaviour.Initialization)\n", @@ -89,14 +93,32 @@ "source": [ "## Dynamic Simulation\n", "def run_simulation(fillin, btf, partial):\n", - " dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name)\n", + " dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name)\n", " reader2 = dpsimpy.CIMReader(sim_name, log_level, log_level)\n", " if sg_type == \"3\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG3OrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG3OrderVBR,\n", + " )\n", " elif sg_type == \"4\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG4OrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG4OrderVBR,\n", + " )\n", " elif sg_type == \"6b\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG6bOrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG6bOrderVBR,\n", + " )\n", " else:\n", " raise Exception(\"Unsupported reduced-order SG type!\")\n", "\n", @@ -104,19 +126,19 @@ "\n", " if with_fault == True:\n", " n1_dp = dpsimpy.dp.SimNode(fault_bus_name, dpsimpy.PhaseType.Single)\n", - " fault_dp.set_parameters(1e12, 0.02*529)\n", + " fault_dp.set_parameters(1e12, 0.02 * 529)\n", " fault_dp.connect([dpsimpy.dp.SimNode.gnd, n1_dp])\n", " fault_dp.open()\n", " sys.add(fault_dp)\n", "\n", " sys.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", " for comp in sys.components:\n", - " # I assume this is how you access the generators\n", - " if \"GEN\" in comp.name():\n", - " comp.scale_inertia_constant(intertia_scaling_factor)\n", - " comp.set_model_as_norton_source(False)\n", + " # I assume this is how you access the generators\n", + " if \"GEN\" in comp.name():\n", + " comp.scale_inertia_constant(intertia_scaling_factor)\n", + " comp.set_model_as_norton_source(False)\n", "\n", - " logger = dpsimpy.Logger(sim_name)#, True, log_down_sampling)\n", + " logger = dpsimpy.Logger(sim_name) # , True, log_down_sampling)\n", " for node in sys.nodes:\n", " logger.log_attribute(node.name() + \".V\", node.attr(\"v\"))\n", "\n", @@ -126,7 +148,7 @@ " logger.log_attribute(comp.name() + \".Te\", comp.attr(\"Te\"))\n", " logger.log_attribute(comp.name() + \".omega\", comp.attr(\"w_r\"))\n", " logger.log_attribute(comp.name() + \".delta\", comp.attr(\"delta\"))\n", - " \n", + "\n", " config = dpsimpy.DirectLinearSolverConfiguration()\n", " config.set_btf(btf)\n", " config.set_fill_in_reduction_method(fillin)\n", @@ -167,8 +189,12 @@ "partial = dpsimpy.partial_refactorization_method.factorization_path\n", "\n", "run_simulation(fillin, btf, partial)\n", - "ts_dpsim_lv_amd = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_amd = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_amd = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_amd = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -184,8 +210,12 @@ "partial = dpsimpy.partial_refactorization_method.factorization_path\n", "\n", "run_simulation(fillin, btf, partial)\n", - "ts_dpsim_lv_amd_nv = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_amd_nv = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_amd_nv = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_amd_nv = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -201,8 +231,12 @@ "partial = dpsimpy.partial_refactorization_method.refactorization_restart\n", "\n", "run_simulation(fillin, btf, partial)\n", - "ts_dpsim_lv_amd_ra = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_amd_ra = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_amd_ra = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_amd_ra = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -219,24 +253,24 @@ " amd_nv_values = ts_dpsim_rv_amd_nv[entry].values\n", " amd_ra_values = ts_dpsim_rv_amd_ra[entry].values\n", " # 2-norm of errors\n", - " error_1 = np.linalg.norm(amd_values-amd_nv_values, ord=2)\n", - " error_2 = np.linalg.norm(amd_ra_values-amd_values, ord=2)\n", - " print('RV Error for {} for AMD vs NV: {}'.format(entry,error_1))\n", - " print('RV Error for {} for AMD vs RA: {}'.format(entry,error_2))\n", - " assert(error_1 < tolerance)\n", - " assert(error_2 < tolerance)\n", + " error_1 = np.linalg.norm(amd_values - amd_nv_values, ord=2)\n", + " error_2 = np.linalg.norm(amd_ra_values - amd_values, ord=2)\n", + " print(\"RV Error for {} for AMD vs NV: {}\".format(entry, error_1))\n", + " print(\"RV Error for {} for AMD vs RA: {}\".format(entry, error_2))\n", + " assert error_1 < tolerance\n", + " assert error_2 < tolerance\n", "\n", "for entry in ts_dpsim_lv_amd:\n", " amd_values = ts_dpsim_lv_amd[entry].values\n", " amd_nv_values = ts_dpsim_lv_amd_nv[entry].values\n", " amd_ra_values = ts_dpsim_lv_amd_ra[entry].values\n", " # 2-norm of errors\n", - " error_1 = np.linalg.norm(amd_values-amd_nv_values, ord=2)\n", - " error_2 = np.linalg.norm(amd_ra_values-amd_values, ord=2)\n", - " print('LV Error for {} for AMD vs NV: {}'.format(entry,error_1))\n", - " print('LV Error for {} for AMD vs RA: {}'.format(entry,error_2))\n", - " assert(error_1 < tolerance)\n", - " assert(error_2 < tolerance)" + " error_1 = np.linalg.norm(amd_values - amd_nv_values, ord=2)\n", + " error_2 = np.linalg.norm(amd_ra_values - amd_values, ord=2)\n", + " print(\"LV Error for {} for AMD vs NV: {}\".format(entry, error_1))\n", + " print(\"LV Error for {} for AMD vs RA: {}\".format(entry, error_2))\n", + " assert error_1 < tolerance\n", + " assert error_2 < tolerance" ] }, { diff --git a/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_SparseLU_DenseLU_KLU_using_partial_refactorization.ipynb b/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_SparseLU_DenseLU_KLU_using_partial_refactorization.ipynb index a50001c5db..3092c57af3 100644 --- a/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_SparseLU_DenseLU_KLU_using_partial_refactorization.ipynb +++ b/examples/Notebooks/Performance/DP_WSCC9bus_SGReducedOrderVBR_validate_SparseLU_DenseLU_KLU_using_partial_refactorization.ipynb @@ -45,34 +45,38 @@ "else:\n", " log_down_sampling = 1.0\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "filename = 'WSCC-09_Dyn_Fourth'\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", - "download_grid_data(filename+'_DI.xml', url+'_DI.xml')\n", - " \n", - "files = glob.glob(filename+'_*.xml')\n", + "filename = \"WSCC-09_Dyn_Fourth\"\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_Dyn_Fourth/WSCC-09_Dyn_Fourth\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "download_grid_data(filename + \"_DI.xml\", url + \"_DI.xml\")\n", "\n", - "dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name_pf)\n", + "files = glob.glob(filename + \"_*.xml\")\n", + "\n", + "dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name_pf)\n", "reader = dpsimpy.CIMReader(sim_name_pf, log_level, log_level)\n", "\n", - "system_pf = reader.loadCIM(60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)\n", - "system_pf.component('GEN1').modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", + "system_pf = reader.loadCIM(\n", + " 60, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")\n", + "system_pf.component(\"GEN1\").modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD)\n", "logger_pf = dpsimpy.Logger(sim_name_pf)\n", "for node in system_pf.nodes:\n", " logger_pf.log_attribute(node.name() + \".V\", node.attr(\"v\"))\n", - " \n", + "\n", "sim_pf = dpsimpy.Simulation(sim_name_pf, log_level)\n", "sim_pf.set_system(system_pf)\n", "sim_pf.set_time_step(final_time)\n", - "sim_pf.set_final_time(2*final_time)\n", + "sim_pf.set_final_time(2 * final_time)\n", "sim_pf.set_domain(dpsimpy.Domain.SP)\n", "sim_pf.set_solver(dpsimpy.Solver.NRP)\n", "sim_pf.set_solver_component_behaviour(dpsimpy.SolverBehaviour.Initialization)\n", @@ -90,14 +94,32 @@ "source": [ "## Dynamic Simulation\n", "def run_simulation(implementation):\n", - " dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name)\n", + " dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name)\n", " reader2 = dpsimpy.CIMReader(sim_name, log_level, log_level)\n", " if sg_type == \"3\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG3OrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG3OrderVBR,\n", + " )\n", " elif sg_type == \"4\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG4OrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG4OrderVBR,\n", + " )\n", " elif sg_type == \"6b\":\n", - " sys = reader2.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.SG6bOrderVBR)\n", + " sys = reader2.loadCIM(\n", + " 60,\n", + " files,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.SG6bOrderVBR,\n", + " )\n", " else:\n", " raise Exception(\"Unsupported reduced-order SG type!\")\n", "\n", @@ -105,19 +127,19 @@ "\n", " if with_fault == True:\n", " n1_dp = dpsimpy.dp.SimNode(fault_bus_name, dpsimpy.PhaseType.Single)\n", - " fault_dp.set_parameters(1e12, 0.02*529)\n", + " fault_dp.set_parameters(1e12, 0.02 * 529)\n", " fault_dp.connect([dpsimpy.dp.SimNode.gnd, n1_dp])\n", " fault_dp.open()\n", " sys.add(fault_dp)\n", "\n", " sys.init_with_powerflow(system_pf, dpsimpy.Domain.DP)\n", " for comp in sys.components:\n", - " # I assume this is how you access the generators\n", - " if \"GEN\" in comp.name():\n", - " comp.scale_inertia_constant(intertia_scaling_factor)\n", - " comp.set_model_as_norton_source(False)\n", + " # I assume this is how you access the generators\n", + " if \"GEN\" in comp.name():\n", + " comp.scale_inertia_constant(intertia_scaling_factor)\n", + " comp.set_model_as_norton_source(False)\n", "\n", - " logger = dpsimpy.Logger(sim_name)#, True, log_down_sampling)\n", + " logger = dpsimpy.Logger(sim_name) # , True, log_down_sampling)\n", " for node in sys.nodes:\n", " logger.log_attribute(node.name() + \".V\", node.attr(\"v\"))\n", "\n", @@ -156,8 +178,12 @@ "source": [ "%%capture\n", "run_simulation(dpsimpy.DirectLinearSolverImpl.SparseLU)\n", - "ts_dpsim_lv_sparse = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_sparse = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_sparse = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_sparse = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -169,8 +195,12 @@ "source": [ "%%capture\n", "run_simulation(dpsimpy.DirectLinearSolverImpl.KLU)\n", - "ts_dpsim_lv_klu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_klu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_klu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_klu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -182,8 +212,12 @@ "source": [ "%%capture\n", "run_simulation(dpsimpy.DirectLinearSolverImpl.DenseLU)\n", - "ts_dpsim_lv_denselu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_denselu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_denselu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_denselu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -203,25 +237,35 @@ " sparse_values = ts_dpsim_rv_sparse[entry].values\n", " klu_values = ts_dpsim_rv_klu[entry].values\n", " denselu_values = ts_dpsim_rv_denselu[entry].values\n", - " \n", + "\n", " N = len(klu_values)\n", - " \n", + "\n", " relativ_diff_sparse_klu = np.zeros(N, dtype=complex)\n", " relativ_diff_sparse_denselu = np.zeros(N, dtype=complex)\n", - " \n", - " for i in range(0, N-1):\n", + "\n", + " for i in range(0, N - 1):\n", " if abs(klu_values[i]) > close_to_zero_tolerance:\n", - " relativ_diff_sparse_klu[i] = (sparse_values[i]-klu_values[i])/klu_values[i]\n", - " relativ_diff_sparse_denselu[i] = (sparse_values[i]-denselu_values[i])/klu_values[i]\n", + " relativ_diff_sparse_klu[i] = (\n", + " sparse_values[i] - klu_values[i]\n", + " ) / klu_values[i]\n", + " relativ_diff_sparse_denselu[i] = (\n", + " sparse_values[i] - denselu_values[i]\n", + " ) / klu_values[i]\n", " if relativ_diff_sparse_klu[i] > maxerror:\n", " maxerror = relativ_diff_sparse_klu[i]\n", " if relativ_diff_sparse_denselu[i] > maxerror:\n", " maxerror = relativ_diff_sparse_denselu[i]\n", - " \n", + "\n", " error_1 = np.linalg.norm(relativ_diff_sparse_klu, ord=2)\n", " error_2 = np.linalg.norm(relativ_diff_sparse_denselu, ord=2)\n", - " print('RV Entry {} Maximum Difference of SparseLU vs. KLU: {}'.format(entry,error_1))\n", - " print('RV Entry {} Maximum Difference of DenseLU vs. SparseLU: {}'.format(entry,error_2))\n", + " print(\n", + " \"RV Entry {} Maximum Difference of SparseLU vs. KLU: {}\".format(entry, error_1)\n", + " )\n", + " print(\n", + " \"RV Entry {} Maximum Difference of DenseLU vs. SparseLU: {}\".format(\n", + " entry, error_2\n", + " )\n", + " )\n", " if error_1 > maxerrorn:\n", " maxerrorn = error_1\n", " if error_2 > maxerrorn:\n", @@ -231,32 +275,42 @@ " sparse_values = ts_dpsim_lv_sparse[entry].values\n", " klu_values = ts_dpsim_lv_klu[entry].values\n", " denselu_values = ts_dpsim_lv_denselu[entry].values\n", - " \n", + "\n", " N = len(klu_values)\n", - " \n", + "\n", " relativ_diff_sparse_klu = np.zeros(N, dtype=complex)\n", " relativ_diff_sparse_denselu = np.zeros(N, dtype=complex)\n", - " \n", - " for i in range(0, N-1):\n", + "\n", + " for i in range(0, N - 1):\n", " if abs(klu_values[i]) > close_to_zero_tolerance:\n", - " relativ_diff_sparse_klu[i] = (sparse_values[i]-klu_values[i])/klu_values[i]\n", - " relativ_diff_sparse_denselu[i] = (sparse_values[i]-denselu_values[i])/klu_values[i]\n", + " relativ_diff_sparse_klu[i] = (\n", + " sparse_values[i] - klu_values[i]\n", + " ) / klu_values[i]\n", + " relativ_diff_sparse_denselu[i] = (\n", + " sparse_values[i] - denselu_values[i]\n", + " ) / klu_values[i]\n", " if relativ_diff_sparse_klu[i] > maxerror:\n", " maxerror = relativ_diff_sparse_klu[i]\n", " if relativ_diff_sparse_denselu[i] > maxerror:\n", " maxerror = relativ_diff_sparse_denselu[i]\n", - " \n", + "\n", " error_1 = np.linalg.norm(relativ_diff_sparse_klu, ord=2)\n", " error_2 = np.linalg.norm(relativ_diff_sparse_denselu, ord=2)\n", - " print('LV Entry {} Maximum Difference of SparseLU vs. KLU: {}'.format(entry,error_1))\n", - " print('LV Entry {} Maximum Difference of DenseLU vs. SparseLU: {}'.format(entry,error_2))\n", + " print(\n", + " \"LV Entry {} Maximum Difference of SparseLU vs. KLU: {}\".format(entry, error_1)\n", + " )\n", + " print(\n", + " \"LV Entry {} Maximum Difference of DenseLU vs. SparseLU: {}\".format(\n", + " entry, error_2\n", + " )\n", + " )\n", " if error_1 > maxerrorn:\n", " maxerrorn = error_1\n", " if error_2 > maxerrorn:\n", " maxerrorn = error_2\n", - " \n", - "print('Maximum error in all values: {}'.format(maxerror))\n", - "print('Maximum norm of errors: {}'.format(maxerrorn))" + "\n", + "print(\"Maximum error in all values: {}\".format(maxerror))\n", + "print(\"Maximum norm of errors: {}\".format(maxerrorn))" ] }, { @@ -266,8 +320,8 @@ "metadata": {}, "outputs": [], "source": [ - "assert(maxerror < relative_solver_error_tolerance)\n", - "assert(maxerrorn < relative_solver_error_tolerance)" + "assert maxerror < relative_solver_error_tolerance\n", + "assert maxerrorn < relative_solver_error_tolerance" ] }, { diff --git a/examples/Notebooks/Performance/Inverter_Grid_Perf.ipynb b/examples/Notebooks/Performance/Inverter_Grid_Perf.ipynb index a9d461bb1a..ffa87654b1 100644 --- a/examples/Notebooks/Performance/Inverter_Grid_Perf.ipynb +++ b/examples/Notebooks/Performance/Inverter_Grid_Perf.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "from dpsim.MeasurementUtils import Measurement \n", + "from dpsim.MeasurementUtils import Measurement\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import numpy as np" @@ -25,20 +25,31 @@ "metadata": {}, "outputs": [], "source": [ - "logs_dir = '../../../logs_inverter/'\n", + "logs_dir = \"../../../logs_inverter/\"\n", "seq_mean = []\n", "\n", - "for threads in range(0,13,2): \n", + "for threads in range(0, 13, 2):\n", " seq_meas = []\n", - " for seq in range(1,11):\n", - " log_path = logs_dir + 'DP_Inverter_Grid_Parallel_FreqSplit_t' + str(threads) + '_s' + str(seq) + '/' + \\\n", - " 'DP_Inverter_Grid_Parallel_FreqSplit_t' + str(threads) + '_s' + str(seq) + '_step_times.log' \n", - " #print(log_path)\n", - " meas = Measurement.read_timestep_csv(log_path)['step_time'].data\n", + " for seq in range(1, 11):\n", + " log_path = (\n", + " logs_dir\n", + " + \"DP_Inverter_Grid_Parallel_FreqSplit_t\"\n", + " + str(threads)\n", + " + \"_s\"\n", + " + str(seq)\n", + " + \"/\"\n", + " + \"DP_Inverter_Grid_Parallel_FreqSplit_t\"\n", + " + str(threads)\n", + " + \"_s\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", + " # print(log_path)\n", + " meas = Measurement.read_timestep_csv(log_path)[\"step_time\"].data\n", " # aggregate the measurements from the different iterations\n", - " seq_meas = np.concatenate( (seq_meas, meas), axis=0 )\n", - " #print(seq_meas.shape)\n", - " seq_mean.append({'threads': threads, 'values': seq_meas.mean()}) \n", + " seq_meas = np.concatenate((seq_meas, meas), axis=0)\n", + " # print(seq_meas.shape)\n", + " seq_mean.append({\"threads\": threads, \"values\": seq_meas.mean()})\n", "\n", "pd_mean_freqsplit = pd.DataFrame(seq_mean)" ] @@ -58,20 +69,31 @@ "metadata": {}, "outputs": [], "source": [ - "logs_dir = '../../../logs_inverter/'\n", + "logs_dir = \"../../../logs_inverter/\"\n", "seq_mean = []\n", "\n", - "for threads in range(0,13,2): \n", + "for threads in range(0, 13, 2):\n", " seq_meas = []\n", - " for seq in range(1,11):\n", - " log_path = logs_dir + 'DP_Inverter_Grid_Parallel_t' + str(threads) + '_s' + str(seq) + '/' + \\\n", - " 'DP_Inverter_Grid_Parallel_t' + str(threads) + '_s' + str(seq) + '_step_times.log' \n", - " #print(log_path)\n", - " meas = Measurement.read_timestep_csv(log_path)['step_time'].data\n", + " for seq in range(1, 11):\n", + " log_path = (\n", + " logs_dir\n", + " + \"DP_Inverter_Grid_Parallel_t\"\n", + " + str(threads)\n", + " + \"_s\"\n", + " + str(seq)\n", + " + \"/\"\n", + " + \"DP_Inverter_Grid_Parallel_t\"\n", + " + str(threads)\n", + " + \"_s\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", + " # print(log_path)\n", + " meas = Measurement.read_timestep_csv(log_path)[\"step_time\"].data\n", " # aggregate the measurements from the different iterations\n", - " seq_meas = np.concatenate( (seq_meas, meas), axis=0 )\n", - " #print(seq_meas.shape)\n", - " seq_mean.append({'threads': threads, 'values': seq_meas.mean()}) \n", + " seq_meas = np.concatenate((seq_meas, meas), axis=0)\n", + " # print(seq_meas.shape)\n", + " seq_mean.append({\"threads\": threads, \"values\": seq_meas.mean()})\n", "\n", "pd_mean_frequnit = pd.DataFrame(seq_mean)" ] @@ -91,19 +113,19 @@ "metadata": {}, "outputs": [], "source": [ - "threads = np.arange(0,13,2) \n", - "plt.plot(threads, pd_mean_freqsplit['values']*1e6, 'o-', label='freq. split')\n", - "plt.plot(threads, pd_mean_frequnit['values']*1e6, 'o-', label='no freq. split')\n", + "threads = np.arange(0, 13, 2)\n", + "plt.plot(threads, pd_mean_freqsplit[\"values\"] * 1e6, \"o-\", label=\"freq. split\")\n", + "plt.plot(threads, pd_mean_frequnit[\"values\"] * 1e6, \"o-\", label=\"no freq. split\")\n", "\n", - "plt.legend(loc='center right')\n", + "plt.legend(loc=\"center right\")\n", "plt.grid()\n", - "#plt.ylim([-0.01,0.2])\n", - "#plt.xlim([0,0.0009])\n", - "plt.xlabel('number of threads')\n", - "plt.ylabel('mean timestep duration (µs)')\n", + "# plt.ylim([-0.01,0.2])\n", + "# plt.xlim([0,0.0009])\n", + "plt.xlabel(\"number of threads\")\n", + "plt.ylabel(\"mean timestep duration (µs)\")\n", "plt.tight_layout()\n", - "plt.savefig('inverter_freq_split.pdf')\n", - "plt.savefig('inverter_freq_split.png', dpi=300)" + "plt.savefig(\"inverter_freq_split.pdf\")\n", + "plt.savefig(\"inverter_freq_split.png\", dpi=300)" ] }, { @@ -119,32 +141,34 @@ "metadata": {}, "outputs": [], "source": [ - "parallel = Measurement.read_timestep_csv('../../../logs/DP_Inverter_Grid_Parallel/DP_Inverter_Grid_Parallel_step_times.log')\n", - "data = parallel['step_time'].data\n", - "xaxis = parallel['step_time'].xaxis\n", + "parallel = Measurement.read_timestep_csv(\n", + " \"../../../logs/DP_Inverter_Grid_Parallel/DP_Inverter_Grid_Parallel_step_times.log\"\n", + ")\n", + "data = parallel[\"step_time\"].data\n", + "xaxis = parallel[\"step_time\"].xaxis\n", "\n", - "print('maximum timestep:')\n", + "print(\"maximum timestep:\")\n", "print(data.max())\n", - "print('standard deviation:')\n", + "print(\"standard deviation:\")\n", "print(data.std())\n", - "print('mean timestep:')\n", + "print(\"mean timestep:\")\n", "print(data.mean())\n", "\n", "plt.figure()\n", "plt.hist(data, 50)\n", - "plt.xlabel('timestep duration (s)')\n", - "plt.ylabel('number of timesteps')\n", - "#plt.xlim([0.0001,0.0005])\n", + "plt.xlabel(\"timestep duration (s)\")\n", + "plt.ylabel(\"number of timesteps\")\n", + "# plt.xlim([0.0001,0.0005])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_hist.png')\n", + "# plt.savefig('parallel_rt_nolog_hist.png')\n", "\n", "plt.figure()\n", "plt.plot(xaxis, data)\n", - "plt.xlabel('timestep index')\n", - "plt.ylabel('timestep duration (s)')\n", - "#plt.ylim([0.0001,0.0006])\n", + "plt.xlabel(\"timestep index\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", + "# plt.ylim([0.0001,0.0006])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_time.png')" + "# plt.savefig('parallel_rt_nolog_time.png')" ] }, { @@ -160,32 +184,34 @@ "metadata": {}, "outputs": [], "source": [ - "sequential = Measurement.read_timestep_csv('../../../logs/DP_Inverter_Grid_Sequential/DP_Inverter_Grid_Sequential_step_times.log')\n", - "data = sequential['step_time'].data\n", - "xaxis = sequential['step_time'].xaxis\n", + "sequential = Measurement.read_timestep_csv(\n", + " \"../../../logs/DP_Inverter_Grid_Sequential/DP_Inverter_Grid_Sequential_step_times.log\"\n", + ")\n", + "data = sequential[\"step_time\"].data\n", + "xaxis = sequential[\"step_time\"].xaxis\n", "\n", - "print('maximum timestep:')\n", + "print(\"maximum timestep:\")\n", "print(data.max())\n", - "print('standard deviation:')\n", + "print(\"standard deviation:\")\n", "print(data.std())\n", - "print('mean timestep:')\n", + "print(\"mean timestep:\")\n", "print(data.mean())\n", "\n", "plt.figure()\n", "plt.hist(data, 50)\n", - "plt.xlabel('timestep duration (s)')\n", - "plt.ylabel('number of timesteps')\n", - "#plt.xlim([0.0001,0.0005])\n", + "plt.xlabel(\"timestep duration (s)\")\n", + "plt.ylabel(\"number of timesteps\")\n", + "# plt.xlim([0.0001,0.0005])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_hist.png')\n", + "# plt.savefig('parallel_rt_nolog_hist.png')\n", "\n", "plt.figure()\n", "plt.plot(xaxis, data)\n", - "plt.xlabel('timestep index')\n", - "plt.ylabel('timestep duration (s)')\n", - "#plt.ylim([0.0001,0.0006])\n", + "plt.xlabel(\"timestep index\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", + "# plt.ylim([0.0001,0.0006])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_time.png')" + "# plt.savefig('parallel_rt_nolog_time.png')" ] }, { @@ -201,32 +227,34 @@ "metadata": {}, "outputs": [], "source": [ - "parallel_splitFreq = Measurement.read_timestep_csv('../../../logs/DP_Inverter_Grid_Parallel_FreqSplit/DP_Inverter_Grid_Parallel_FreqSplit_step_times.log')\n", - "data = parallel_splitFreq['step_time'].data\n", - "xaxis = parallel_splitFreq['step_time'].xaxis\n", + "parallel_splitFreq = Measurement.read_timestep_csv(\n", + " \"../../../logs/DP_Inverter_Grid_Parallel_FreqSplit/DP_Inverter_Grid_Parallel_FreqSplit_step_times.log\"\n", + ")\n", + "data = parallel_splitFreq[\"step_time\"].data\n", + "xaxis = parallel_splitFreq[\"step_time\"].xaxis\n", "\n", - "print('maximum timestep:')\n", + "print(\"maximum timestep:\")\n", "print(data.max())\n", - "print('standard deviation:')\n", + "print(\"standard deviation:\")\n", "print(data.std())\n", - "print('mean timestep:')\n", + "print(\"mean timestep:\")\n", "print(data.mean())\n", "\n", "plt.figure()\n", "plt.hist(data, 50)\n", - "plt.xlabel('timestep duration (s)')\n", - "plt.ylabel('number of timesteps')\n", - "#plt.xlim([0.0001,0.0005])\n", + "plt.xlabel(\"timestep duration (s)\")\n", + "plt.ylabel(\"number of timesteps\")\n", + "# plt.xlim([0.0001,0.0005])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_hist.png')\n", + "# plt.savefig('parallel_rt_nolog_hist.png')\n", "\n", "plt.figure()\n", "plt.plot(xaxis, data)\n", - "plt.xlabel('timestep index')\n", - "plt.ylabel('timestep duration (s)')\n", - "#plt.ylim([0.0001,0.0006])\n", + "plt.xlabel(\"timestep index\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", + "# plt.ylim([0.0001,0.0006])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_time.png')" + "# plt.savefig('parallel_rt_nolog_time.png')" ] }, { @@ -242,32 +270,34 @@ "metadata": {}, "outputs": [], "source": [ - "sequential_SplitFreq = Measurement.read_timestep_csv('../../../logs/DP_Inverter_Grid_Sequential_FreqSplit/DP_Inverter_Grid_Sequential_FreqSplit_step_times.log')\n", - "data = sequential_SplitFreq['step_time'].data\n", - "xaxis = sequential_SplitFreq['step_time'].xaxis\n", + "sequential_SplitFreq = Measurement.read_timestep_csv(\n", + " \"../../../logs/DP_Inverter_Grid_Sequential_FreqSplit/DP_Inverter_Grid_Sequential_FreqSplit_step_times.log\"\n", + ")\n", + "data = sequential_SplitFreq[\"step_time\"].data\n", + "xaxis = sequential_SplitFreq[\"step_time\"].xaxis\n", "\n", - "print('maximum timestep:')\n", + "print(\"maximum timestep:\")\n", "print(data.max())\n", - "print('standard deviation:')\n", + "print(\"standard deviation:\")\n", "print(data.std())\n", - "print('mean timestep:')\n", + "print(\"mean timestep:\")\n", "print(data.mean())\n", "\n", "plt.figure()\n", "plt.hist(data, 50)\n", - "plt.xlabel('timestep duration (s)')\n", - "plt.ylabel('number of timesteps')\n", - "#plt.xlim([0.0001,0.0005])\n", + "plt.xlabel(\"timestep duration (s)\")\n", + "plt.ylabel(\"number of timesteps\")\n", + "# plt.xlim([0.0001,0.0005])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_hist.png')\n", + "# plt.savefig('parallel_rt_nolog_hist.png')\n", "\n", "plt.figure()\n", "plt.plot(xaxis, data)\n", - "plt.xlabel('timestep index')\n", - "plt.ylabel('timestep duration (s)')\n", - "#plt.ylim([0.0001,0.0006])\n", + "plt.xlabel(\"timestep index\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", + "# plt.ylim([0.0001,0.0006])\n", "plt.grid()\n", - "#plt.savefig('parallel_rt_nolog_time.png')" + "# plt.savefig('parallel_rt_nolog_time.png')" ] }, { @@ -283,28 +313,28 @@ "metadata": {}, "outputs": [], "source": [ - "parallel_data = parallel['step_time'].data\n", - "parallel_xaxis = parallel['step_time'].xaxis\n", - "sequential_data = sequential['step_time'].data\n", - "sequential_xaxis = sequential['step_time'].xaxis\n", - "parallel_splitFreq_data = parallel_splitFreq['step_time'].data\n", - "parallel_splitFreq_xaxis = parallel_splitFreq['step_time'].xaxis\n", - "sequential_SplitFreq_data = sequential_SplitFreq['step_time'].data\n", - "sequential_SplitFreq_xaxis = sequential_SplitFreq['step_time'].xaxis\n", + "parallel_data = parallel[\"step_time\"].data\n", + "parallel_xaxis = parallel[\"step_time\"].xaxis\n", + "sequential_data = sequential[\"step_time\"].data\n", + "sequential_xaxis = sequential[\"step_time\"].xaxis\n", + "parallel_splitFreq_data = parallel_splitFreq[\"step_time\"].data\n", + "parallel_splitFreq_xaxis = parallel_splitFreq[\"step_time\"].xaxis\n", + "sequential_SplitFreq_data = sequential_SplitFreq[\"step_time\"].data\n", + "sequential_SplitFreq_xaxis = sequential_SplitFreq[\"step_time\"].xaxis\n", "\n", "plt.figure()\n", - "plt.hist(parallel_data, 50, label='parallel')\n", - "plt.hist(sequential_data, 50, label='sequential')\n", - "plt.hist(parallel_splitFreq_data, 50, label='parallel_freq_split')\n", - "plt.hist(sequential_SplitFreq_data, 50, label='sequential_freq_split')\n", - "plt.xlabel('timestep duration (s)')\n", - "plt.ylabel('number of timesteps')\n", + "plt.hist(parallel_data, 50, label=\"parallel\")\n", + "plt.hist(sequential_data, 50, label=\"sequential\")\n", + "plt.hist(parallel_splitFreq_data, 50, label=\"parallel_freq_split\")\n", + "plt.hist(sequential_SplitFreq_data, 50, label=\"sequential_freq_split\")\n", + "plt.xlabel(\"timestep duration (s)\")\n", + "plt.ylabel(\"number of timesteps\")\n", "plt.grid()\n", "ax = plt.gca()\n", "ax.xaxis.set_major_locator(plt.MaxNLocator(5))\n", "ax.legend()\n", - "#plt.xlim([0.0001,0.0005])\n", - "#plt.savefig('parallel_single_rt_nolog_hist.pdf')" + "# plt.xlim([0.0001,0.0005])\n", + "# plt.savefig('parallel_single_rt_nolog_hist.pdf')" ] }, { @@ -314,16 +344,18 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(parallel_xaxis, parallel_data, label='parallel')\n", - "plt.plot(sequential_xaxis, sequential_data, label='sequential')\n", - "plt.plot(parallel_splitFreq_xaxis, parallel_splitFreq_data, label='parallel_freq_split')\n", - "plt.plot(sequential_SplitFreq_xaxis, sequential_SplitFreq_data, label='sequential_freq_split')\n", - "plt.xlabel('timestep index')\n", - "plt.ylabel('timestep duration (s)')\n", - "plt.legend(loc='lower right')\n", + "plt.plot(parallel_xaxis, parallel_data, label=\"parallel\")\n", + "plt.plot(sequential_xaxis, sequential_data, label=\"sequential\")\n", + "plt.plot(parallel_splitFreq_xaxis, parallel_splitFreq_data, label=\"parallel_freq_split\")\n", + "plt.plot(\n", + " sequential_SplitFreq_xaxis, sequential_SplitFreq_data, label=\"sequential_freq_split\"\n", + ")\n", + "plt.xlabel(\"timestep index\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", + "plt.legend(loc=\"lower right\")\n", "plt.grid()\n", - "#plt.ylim([0.0001,0.0006])\n", - "#plt.savefig('parallel_single_rt_nolog_time.pdf')" + "# plt.ylim([0.0001,0.0006])\n", + "# plt.savefig('parallel_single_rt_nolog_time.pdf')" ] }, { diff --git a/examples/Notebooks/Performance/WSCC_9bus_iterations.ipynb b/examples/Notebooks/Performance/WSCC_9bus_iterations.ipynb index d33271b80b..7d4c383cb9 100644 --- a/examples/Notebooks/Performance/WSCC_9bus_iterations.ipynb +++ b/examples/Notebooks/Performance/WSCC_9bus_iterations.ipynb @@ -16,18 +16,42 @@ "import pandas as pd\n", "from dpsim.MeasurementUtils import Measurement\n", "\n", - "logs_dir = '../../../logs_rt_char/'\n", + "logs_dir = \"../../../logs_rt_char/\"\n", "decoupled_meas = []\n", "copies = 10\n", "threads = 8\n", - " \n", - "for seq in range(1,1001): \n", - " sim_dir = logs_dir + 'WSCC_9bus_decoupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '/'\n", - " log_name = 'WSCC_9bus_decoupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '_step_times.log'\n", + "\n", + "for seq in range(1, 1001):\n", + " sim_dir = (\n", + " logs_dir\n", + " + \"WSCC_9bus_decoupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"/\"\n", + " )\n", + " log_name = (\n", + " \"WSCC_9bus_decoupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", " log_path = sim_dir + log_name\n", - " #print(log_path) \n", + " # print(log_path)\n", " meas = Measurement.read_timestep_csv(log_path)\n", - " decoupled_meas.append({'copies': copies, 'threads': threads, 'sequence': seq, 'values': meas['step_time'].data}) \n", + " decoupled_meas.append(\n", + " {\n", + " \"copies\": copies,\n", + " \"threads\": threads,\n", + " \"sequence\": seq,\n", + " \"values\": meas[\"step_time\"].data,\n", + " }\n", + " )\n", "\n", "pd_decoupled_meas = pd.DataFrame(decoupled_meas)" ] @@ -45,9 +69,14 @@ "metadata": {}, "outputs": [], "source": [ - "for seq in range(1,1001):\n", - " if pd_decoupled_meas.query('sequence == ' + str(seq))['values'].values[0][10:].argmax() == 0:\n", - " print('first entry') " + "for seq in range(1, 1001):\n", + " if (\n", + " pd_decoupled_meas.query(\"sequence == \" + str(seq))[\"values\"]\n", + " .values[0][10:]\n", + " .argmax()\n", + " == 0\n", + " ):\n", + " print(\"first entry\")" ] }, { @@ -66,11 +95,15 @@ "source": [ "decoupled_max = []\n", "absolute_max = 0\n", - "for seq in range(1,1001):\n", - " current_max = pd_decoupled_meas.query('sequence == ' + str(seq))['values'].values[0][10:].max()\n", + "for seq in range(1, 1001):\n", + " current_max = (\n", + " pd_decoupled_meas.query(\"sequence == \" + str(seq))[\"values\"]\n", + " .values[0][10:]\n", + " .max()\n", + " )\n", " if current_max > absolute_max:\n", " absolute_max = current_max\n", - " decoupled_max.append(absolute_max) " + " decoupled_max.append(absolute_max)" ] }, { @@ -81,15 +114,15 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", - "plt.figure(figsize=(12/2.54,8/2.54))\n", - "plt.plot(decoupled_max, label='real time')\n", - "plt.ticklabel_format(axis='y', style='sci', scilimits=(-3,3))\n", - "plt.xlabel('iterations')\n", - "plt.ylabel('timestep duration (s)')\n", + "plt.figure(figsize=(12 / 2.54, 8 / 2.54))\n", + "plt.plot(decoupled_max, label=\"real time\")\n", + "plt.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(-3, 3))\n", + "plt.xlabel(\"iterations\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('wscc_9bus_iter_rt_max.pdf')" + "plt.savefig(\"wscc_9bus_iter_rt_max.pdf\")" ] }, { @@ -108,10 +141,22 @@ "import numpy as np\n", "\n", "decoupled_concat = []\n", - "decoupled_concat.append(pd_decoupled_meas.query('sequence == 1')['values'].values[0][10:])\n", + "decoupled_concat.append(\n", + " pd_decoupled_meas.query(\"sequence == 1\")[\"values\"].values[0][10:]\n", + ")\n", "\n", - "for seq in range(2,1001):\n", - " decoupled_concat.append( np.concatenate( (decoupled_concat[-1], pd_decoupled_meas.query('sequence == ' + str(seq))['values'].values[0][10:]), axis=0 ) )" + "for seq in range(2, 1001):\n", + " decoupled_concat.append(\n", + " np.concatenate(\n", + " (\n", + " decoupled_concat[-1],\n", + " pd_decoupled_meas.query(\"sequence == \" + str(seq))[\"values\"].values[0][\n", + " 10:\n", + " ],\n", + " ),\n", + " axis=0,\n", + " )\n", + " )" ] }, { @@ -122,7 +167,7 @@ "source": [ "decoupled_mean = []\n", "\n", - "for seq in range(0,1000):\n", + "for seq in range(0, 1000):\n", " decoupled_mean.append(decoupled_concat[seq].mean())" ] }, @@ -132,14 +177,14 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12/2.54,8/2.54))\n", + "plt.figure(figsize=(12 / 2.54, 8 / 2.54))\n", "plt.plot(decoupled_mean)\n", - "plt.ticklabel_format(axis='y', style='sci', scilimits=(-3,3))\n", - "plt.xlabel('iterations')\n", - "plt.ylabel('timestep duration (s)')\n", + "plt.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(-3, 3))\n", + "plt.xlabel(\"iterations\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", "plt.grid()\n", "plt.tight_layout()\n", - "plt.savefig('wscc_9bus_iter_rt_mean.pdf')" + "plt.savefig(\"wscc_9bus_iter_rt_mean.pdf\")" ] }, { @@ -150,7 +195,7 @@ "source": [ "decoupled_std = []\n", "\n", - "for seq in range(0,1000): \n", + "for seq in range(0, 1000):\n", " decoupled_std.append(decoupled_concat[seq].std())" ] }, @@ -160,14 +205,14 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12/2.54,8/2.54))\n", + "plt.figure(figsize=(12 / 2.54, 8 / 2.54))\n", "plt.plot(decoupled_std)\n", - "plt.ticklabel_format(axis='y', style='sci', scilimits=(-3,3))\n", - "plt.xlabel('iterations')\n", - "plt.ylabel('timestep duration (s)')\n", + "plt.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(-3, 3))\n", + "plt.xlabel(\"iterations\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", "plt.grid()\n", "plt.tight_layout()\n", - "plt.savefig('wscc_9bus_iter_rt_std.pdf')" + "plt.savefig(\"wscc_9bus_iter_rt_std.pdf\")" ] }, { @@ -186,18 +231,42 @@ "import pandas as pd\n", "from dpsim.MeasurementUtils import Measurement\n", "\n", - "logs_dir = '../../../logs_tp_char/'\n", + "logs_dir = \"../../../logs_tp_char/\"\n", "tp_decoupled_meas = []\n", "copies = 10\n", "threads = 8\n", - " \n", - "for seq in range(1,1001): \n", - " sim_dir = logs_dir + 'WSCC_9bus_decoupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '/'\n", - " log_name = 'WSCC_9bus_decoupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '_step_times.log'\n", + "\n", + "for seq in range(1, 1001):\n", + " sim_dir = (\n", + " logs_dir\n", + " + \"WSCC_9bus_decoupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"/\"\n", + " )\n", + " log_name = (\n", + " \"WSCC_9bus_decoupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", " log_path = sim_dir + log_name\n", - " #print(log_path) \n", + " # print(log_path)\n", " meas = Measurement.read_timestep_csv(log_path)\n", - " tp_decoupled_meas.append({'copies': copies, 'threads': threads, 'sequence': seq, 'values': meas['step_time'].data}) \n", + " tp_decoupled_meas.append(\n", + " {\n", + " \"copies\": copies,\n", + " \"threads\": threads,\n", + " \"sequence\": seq,\n", + " \"values\": meas[\"step_time\"].data,\n", + " }\n", + " )\n", "\n", "tp_pd_decoupled_meas = pd.DataFrame(tp_decoupled_meas)" ] @@ -212,11 +281,15 @@ "\n", "tp_decoupled_max = []\n", "absolute_max = 0\n", - "for seq in range(1,1000):\n", - " current_max = tp_pd_decoupled_meas.query('sequence == ' + str(seq))['values'].values[0][10:].max()\n", + "for seq in range(1, 1000):\n", + " current_max = (\n", + " tp_pd_decoupled_meas.query(\"sequence == \" + str(seq))[\"values\"]\n", + " .values[0][10:]\n", + " .max()\n", + " )\n", " if current_max > absolute_max:\n", " absolute_max = current_max\n", - " tp_decoupled_max.append(absolute_max) " + " tp_decoupled_max.append(absolute_max)" ] }, { @@ -225,17 +298,17 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12/2.54,8/2.54))\n", - "#plt.plot(decoupled_max, label='real time')\n", - "plt.plot(tp_decoupled_max, label='throughput')\n", - "plt.ticklabel_format(axis='y', style='sci', scilimits=(-3,3))\n", - "plt.xlabel('iterations')\n", - "plt.ylabel('timestep duration (s)')\n", + "plt.figure(figsize=(12 / 2.54, 8 / 2.54))\n", + "# plt.plot(decoupled_max, label='real time')\n", + "plt.plot(tp_decoupled_max, label=\"throughput\")\n", + "plt.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(-3, 3))\n", + "plt.xlabel(\"iterations\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", "plt.grid()\n", "ax = plt.gca()\n", - "#ax.legend()\n", + "# ax.legend()\n", "plt.tight_layout()\n", - "plt.savefig('wscc_9bus_iter_tp_max.pdf')" + "plt.savefig(\"wscc_9bus_iter_tp_max.pdf\")" ] }, { @@ -245,10 +318,22 @@ "outputs": [], "source": [ "tp_decoupled_concat = []\n", - "tp_decoupled_concat.append(tp_pd_decoupled_meas.query('sequence == 1')['values'].values[0][10:])\n", + "tp_decoupled_concat.append(\n", + " tp_pd_decoupled_meas.query(\"sequence == 1\")[\"values\"].values[0][10:]\n", + ")\n", "\n", - "for seq in range(2,1001):\n", - " tp_decoupled_concat.append( np.concatenate( (tp_decoupled_concat[-1], tp_pd_decoupled_meas.query('sequence == ' + str(seq))['values'].values[0][10:]), axis=0 ) )" + "for seq in range(2, 1001):\n", + " tp_decoupled_concat.append(\n", + " np.concatenate(\n", + " (\n", + " tp_decoupled_concat[-1],\n", + " tp_pd_decoupled_meas.query(\"sequence == \" + str(seq))[\"values\"].values[\n", + " 0\n", + " ][10:],\n", + " ),\n", + " axis=0,\n", + " )\n", + " )" ] }, { @@ -259,7 +344,7 @@ "source": [ "tp_decoupled_mean = []\n", "\n", - "for seq in range(0,1000):\n", + "for seq in range(0, 1000):\n", " tp_decoupled_mean.append(tp_decoupled_concat[seq].mean())" ] }, @@ -269,15 +354,15 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12/2.54,8/2.54))\n", - "#plt.plot(decoupled_mean, label='real time')\n", - "plt.plot(tp_decoupled_mean, label='throughput')\n", - "plt.ticklabel_format(axis='y', style='sci', scilimits=(-3,3))\n", - "plt.xlabel('iterations')\n", - "plt.ylabel('timestep duration (s)')\n", + "plt.figure(figsize=(12 / 2.54, 8 / 2.54))\n", + "# plt.plot(decoupled_mean, label='real time')\n", + "plt.plot(tp_decoupled_mean, label=\"throughput\")\n", + "plt.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(-3, 3))\n", + "plt.xlabel(\"iterations\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", "plt.grid()\n", "plt.tight_layout()\n", - "plt.savefig('wscc_9bus_iter_tp_mean.pdf')" + "plt.savefig(\"wscc_9bus_iter_tp_mean.pdf\")" ] }, { @@ -288,7 +373,7 @@ "source": [ "tp_decoupled_std = []\n", "\n", - "for seq in range(0,1000):\n", + "for seq in range(0, 1000):\n", " tp_decoupled_std.append(tp_decoupled_concat[seq].std())" ] }, @@ -298,14 +383,14 @@ "metadata": {}, "outputs": [], "source": [ - "plt.figure(figsize=(12/2.54,8/2.54))\n", + "plt.figure(figsize=(12 / 2.54, 8 / 2.54))\n", "plt.plot(tp_decoupled_std)\n", - "plt.ticklabel_format(axis='y', style='sci', scilimits=(-3,3))\n", - "plt.xlabel('iterations')\n", - "plt.ylabel('timestep duration (s)')\n", + "plt.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(-3, 3))\n", + "plt.xlabel(\"iterations\")\n", + "plt.ylabel(\"timestep duration (s)\")\n", "plt.grid()\n", "plt.tight_layout()\n", - "plt.savefig('wscc_9bus_iter_tp_std.pdf')" + "plt.savefig(\"wscc_9bus_iter_tp_std.pdf\")" ] }, { diff --git a/examples/Notebooks/Performance/WSCC_9bus_mult_coupled_validate_SparseLU_DenseLU_KLU.ipynb b/examples/Notebooks/Performance/WSCC_9bus_mult_coupled_validate_SparseLU_DenseLU_KLU.ipynb index 336dcc807f..33d08e48ac 100644 --- a/examples/Notebooks/Performance/WSCC_9bus_mult_coupled_validate_SparseLU_DenseLU_KLU.ipynb +++ b/examples/Notebooks/Performance/WSCC_9bus_mult_coupled_validate_SparseLU_DenseLU_KLU.ipynb @@ -27,19 +27,21 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX/WSCC-09_RX'\n", - "filename = 'WSCC-09_RX_WithoutSyngenParams'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", - "download_grid_data(filename+'_DI.xml', url+'_DI.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/WSCC-09/WSCC-09_RX/WSCC-09_RX\"\n", + "filename = \"WSCC-09_RX_WithoutSyngenParams\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "download_grid_data(filename + \"_DI.xml\", url + \"_DI.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -59,16 +61,25 @@ "num_copies = 0\n", "num_threads = 0\n", "num_seq = 0\n", - "sim_name = \"WSCC_9bus_coupled_\" + str(num_copies) + \"_\" + str(num_threads) + \"_\" + str(num_seq)\n", + "sim_name = (\n", + " \"WSCC_9bus_coupled_\" + str(num_copies) + \"_\" + str(num_threads) + \"_\" + str(num_seq)\n", + ")\n", + "\n", "\n", "def simulate_coupled(filenames, copies, threads, seq, implementation):\n", - " dpsimpy.Logger.set_log_dir(log_dir+\"/\"+sim_name)\n", + " dpsimpy.Logger.set_log_dir(log_dir + \"/\" + sim_name)\n", " reader = dpsimpy.CIMReader(sim_name, log_level, log_level)\n", - " sys = reader.loadCIM(60, filenames, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.IdealVoltageSource)\n", - " \n", + " sys = reader.loadCIM(\n", + " 60,\n", + " filenames,\n", + " dpsimpy.Domain.DP,\n", + " dpsimpy.PhaseType.Single,\n", + " dpsimpy.GeneratorType.IdealVoltageSource,\n", + " )\n", + "\n", " # if copies > 0:\n", " # multiply_connected(sys, copies, 12.5, 0.16, 1e-6)\n", - " \n", + "\n", " sim = dpsimpy.Simulation(sim_name, log_level)\n", " sim.set_system(sys)\n", " sim.set_domain(dpsimpy.Domain.DP)\n", @@ -88,8 +99,12 @@ "source": [ "%%capture\n", "simulate_coupled(files, 0, 0, 0, dpsimpy.DirectLinearSolverImpl.SparseLU)\n", - "ts_dpsim_lv_sparse = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_sparse = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_sparse = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_sparse = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -101,8 +116,12 @@ "source": [ "%%capture\n", "simulate_coupled(files, 0, 0, 0, dpsimpy.DirectLinearSolverImpl.KLU)\n", - "ts_dpsim_lv_klu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_klu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_klu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_klu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -114,8 +133,12 @@ "source": [ "%%capture\n", "simulate_coupled(files, 0, 0, 0, dpsimpy.DirectLinearSolverImpl.DenseLU)\n", - "ts_dpsim_lv_denselu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_LeftVector.csv\")\n", - "ts_dpsim_rv_denselu = rt.read_timeseries_dpsim(dpsimpy.Logger.get_log_dir()+\"/\"+sim_name+\"_RightVector.csv\")" + "ts_dpsim_lv_denselu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_LeftVector.csv\"\n", + ")\n", + "ts_dpsim_rv_denselu = rt.read_timeseries_dpsim(\n", + " dpsimpy.Logger.get_log_dir() + \"/\" + sim_name + \"_RightVector.csv\"\n", + ")" ] }, { @@ -132,20 +155,20 @@ " klu_values = ts_dpsim_rv_klu[entry].values\n", " denselu_values = ts_dpsim_rv_denselu[entry].values\n", " # 2-norm of errors\n", - " error_1 = np.linalg.norm(sparse_values-klu_values, ord=2)\n", - " error_2 = np.linalg.norm(denselu_values-sparse_values, ord=2)\n", - " assert(error_1 < tolerance)\n", - " assert(error_2 < tolerance)\n", + " error_1 = np.linalg.norm(sparse_values - klu_values, ord=2)\n", + " error_2 = np.linalg.norm(denselu_values - sparse_values, ord=2)\n", + " assert error_1 < tolerance\n", + " assert error_2 < tolerance\n", "\n", "for entry in ts_dpsim_lv_sparse:\n", " sparse_values = ts_dpsim_lv_sparse[entry].values\n", " klu_values = ts_dpsim_lv_klu[entry].values\n", " denselu_values = ts_dpsim_lv_denselu[entry].values\n", " # 2-norm of errors\n", - " error_1 = np.linalg.norm(sparse_values-klu_values, ord=2)\n", - " error_2 = np.linalg.norm(denselu_values-sparse_values, ord=2)\n", - " assert(error_1 < tolerance)\n", - " assert(error_2 < tolerance)" + " error_1 = np.linalg.norm(sparse_values - klu_values, ord=2)\n", + " error_2 = np.linalg.norm(denselu_values - sparse_values, ord=2)\n", + " assert error_1 < tolerance\n", + " assert error_2 < tolerance" ] } ], diff --git a/examples/Notebooks/Performance/WSCC_9bus_parallel.ipynb b/examples/Notebooks/Performance/WSCC_9bus_parallel.ipynb index 5b7eb8c600..3454ce8c9f 100644 --- a/examples/Notebooks/Performance/WSCC_9bus_parallel.ipynb +++ b/examples/Notebooks/Performance/WSCC_9bus_parallel.ipynb @@ -89,9 +89,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC_9bus_coupled_1_0_0/'\n", - "logName = 'WSCC_9bus_coupled_1_0_0'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC_9bus_coupled_1_0_0/\"\n", + "logName = \"WSCC_9bus_coupled_1_0_0\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_coupled = rt.read_timeseries_dpsim(logFilename)\n", @@ -104,9 +104,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC_9bus_decoupled_1_0_0/'\n", - "logName = 'WSCC_9bus_decoupled_1_0_0'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC_9bus_decoupled_1_0_0/\"\n", + "logName = \"WSCC_9bus_decoupled_1_0_0\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_decoupled = rt.read_timeseries_dpsim(logFilename)\n", @@ -119,13 +119,13 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC_9bus_diakoptics_1_0_0_0/'\n", - "logName = 'WSCC_9bus_diakoptics_1_0_0_0'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC_9bus_diakoptics_1_0_0_0/\"\n", + "logName = \"WSCC_9bus_diakoptics_1_0_0_0\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_diakpotics = rt.read_timeseries_dpsim(logFilename)\n", - "phasors_diakoptics= ts.phasors(ts_diakpotics)" + "phasors_diakoptics = ts.phasors(ts_diakpotics)" ] }, { @@ -135,7 +135,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_coupled.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -145,7 +151,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_decoupled.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -155,7 +167,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_diakoptics.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -171,9 +189,9 @@ "metadata": {}, "outputs": [], "source": [ - "path = 'logs/WSCC-9bus/'\n", - "logName = 'WSCC-9bus'\n", - "logFilename = path + logName + '.csv'\n", + "path = \"logs/WSCC-9bus/\"\n", + "logName = \"WSCC-9bus\"\n", + "logFilename = path + logName + \".csv\"\n", "print(logFilename)\n", "\n", "ts_single = rt.read_timeseries_dpsim(logFilename)\n", @@ -187,7 +205,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_single.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1])\n", + " )" ] }, { @@ -204,7 +228,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_single.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1] - phasors_decoupled[node]['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1] - phasors_decoupled[node]['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1] - phasors_decoupled[node][\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1] - phasors_decoupled[node][\"phase\"].values[-1])\n", + " )" ] }, { @@ -214,7 +244,13 @@ "outputs": [], "source": [ "for node, phasor in phasors_coupled.items():\n", - " print(node + ': ' + str(phasor['abs'].values[-1] - phasors_diakoptics[node]['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1] - phasors_diakoptics[node]['phase'].values[-1]))" + " print(\n", + " node\n", + " + \": \"\n", + " + str(phasor[\"abs\"].values[-1] - phasors_diakoptics[node][\"abs\"].values[-1])\n", + " + \"<\"\n", + " + str(phasor[\"phase\"].values[-1] - phasors_diakoptics[node][\"phase\"].values[-1])\n", + " )" ] }, { @@ -230,35 +266,56 @@ "metadata": {}, "outputs": [], "source": [ - "#%%capture\n", + "# %%capture\n", "import pandas as pd\n", "from dpsim.MeasurementUtils import Measurement\n", "import numpy as np\n", "\n", - "logs_dir = '../../../logs_9bus/'\n", - "#coupled_meas = []\n", + "logs_dir = \"../../../logs_9bus/\"\n", + "# coupled_meas = []\n", "coupled_mean = []\n", "coupled_max = []\n", "coupled_std = []\n", "\n", - "for copies in range(0,20): \n", - " for threads in range(0,13,2): \n", + "for copies in range(0, 20):\n", + " for threads in range(0, 13, 2):\n", " seq_meas = []\n", - " for seq in range(1,11):\n", - " log_path = logs_dir + 'WSCC_9bus_coupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '/' + \\\n", - " 'WSCC_9bus_coupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '_step_times.log' \n", - " #print(log_path)\n", - " meas = Measurement.read_timestep_csv(log_path)['step_time'].data\n", + " for seq in range(1, 11):\n", + " log_path = (\n", + " logs_dir\n", + " + \"WSCC_9bus_coupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"/\"\n", + " + \"WSCC_9bus_coupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", + " # print(log_path)\n", + " meas = Measurement.read_timestep_csv(log_path)[\"step_time\"].data\n", " # aggregate the measurements from the different iterations\n", - " seq_meas = np.concatenate( (seq_meas, meas), axis=0)\n", - " \n", - " #print(seq_meas.shape)\n", - " #coupled_meas.append({'copies': copies, 'threads': threads, 'values': meas['step_time'].data}) \n", - " coupled_mean.append({'copies': copies, 'threads': threads, 'values': seq_meas.mean()}) \n", - " coupled_max.append({'copies': copies, 'threads': threads, 'values': seq_meas.max()}) \n", - " coupled_std.append({'copies': copies, 'threads': threads, 'values': seq_meas.std()}) \n", - " \n", - "#pd_coupled_meas = pd.DataFrame(coupled_meas)\n", + " seq_meas = np.concatenate((seq_meas, meas), axis=0)\n", + "\n", + " # print(seq_meas.shape)\n", + " # coupled_meas.append({'copies': copies, 'threads': threads, 'values': meas['step_time'].data})\n", + " coupled_mean.append(\n", + " {\"copies\": copies, \"threads\": threads, \"values\": seq_meas.mean()}\n", + " )\n", + " coupled_max.append(\n", + " {\"copies\": copies, \"threads\": threads, \"values\": seq_meas.max()}\n", + " )\n", + " coupled_std.append(\n", + " {\"copies\": copies, \"threads\": threads, \"values\": seq_meas.std()}\n", + " )\n", + "\n", + "# pd_coupled_meas = pd.DataFrame(coupled_meas)\n", "pd_coupled_mean = pd.DataFrame(coupled_mean)\n", "pd_coupled_max = pd.DataFrame(coupled_max)\n", "pd_coupled_std = pd.DataFrame(coupled_std)" @@ -275,17 +332,22 @@ "\n", "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(2))\n", - "copies = np.arange(1,21)\n", - "\n", - "for threads in range(0,13,2):\n", - " plt.plot(copies, pd_coupled_mean.query('threads=='+str(threads))['values'].values, label=str(threads)+' threads', marker='o')\n", - "\n", - "plt.xlabel('number of system copies')\n", - "plt.ylabel('mean timestep duration (s)')\n", + "copies = np.arange(1, 21)\n", + "\n", + "for threads in range(0, 13, 2):\n", + " plt.plot(\n", + " copies,\n", + " pd_coupled_mean.query(\"threads==\" + str(threads))[\"values\"].values,\n", + " label=str(threads) + \" threads\",\n", + " marker=\"o\",\n", + " )\n", + "\n", + "plt.xlabel(\"number of system copies\")\n", + "plt.ylabel(\"mean timestep duration (s)\")\n", "plt.grid()\n", - "plt.legend(loc='upper left')\n", + "plt.legend(loc=\"upper left\")\n", "plt.tight_layout()\n", - "plt.savefig('9bus_coupled.pdf')" + "plt.savefig(\"9bus_coupled.pdf\")" ] }, { @@ -297,29 +359,50 @@ "import pandas as pd\n", "from dpsim.MeasurementUtils import Measurement\n", "\n", - "logs_dir = '../../../logs_9bus/'\n", + "logs_dir = \"../../../logs_9bus/\"\n", "decoupled_meas = []\n", "decoupled_mean = []\n", "decoupled_max = []\n", "decoupled_std = []\n", "\n", - "for copies in range(0,20): \n", - " for threads in range(0,13,2): \n", + "for copies in range(0, 20):\n", + " for threads in range(0, 13, 2):\n", " seq_meas = []\n", - " for seq in range(1,11):\n", - " log_path = logs_dir + 'WSCC_9bus_decoupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '/' + \\\n", - " 'WSCC_9bus_decoupled_' + str(copies) + '_' + str(threads) + '_' + str(seq) + '_step_times.log' \n", - " #print(log_path)\n", - " meas = Measurement.read_timestep_csv(log_path)['step_time'].data\n", + " for seq in range(1, 11):\n", + " log_path = (\n", + " logs_dir\n", + " + \"WSCC_9bus_decoupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"/\"\n", + " + \"WSCC_9bus_decoupled_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", + " # print(log_path)\n", + " meas = Measurement.read_timestep_csv(log_path)[\"step_time\"].data\n", " # aggregate the measurements from the different iterations\n", - " seq_meas = np.concatenate( (seq_meas, meas), axis=0)\n", - " \n", - " #print(seq_meas.shape)\n", - " #coupled_meas.append({'copies': copies, 'threads': threads, 'values': meas['step_time'].data}) \n", - " decoupled_mean.append({'copies': copies, 'threads': threads, 'values': seq_meas.mean()}) \n", - " decoupled_max.append({'copies': copies, 'threads': threads, 'values': seq_meas.max()}) \n", - " decoupled_std.append({'copies': copies, 'threads': threads, 'values': seq_meas.std()}) \n", - " \n", + " seq_meas = np.concatenate((seq_meas, meas), axis=0)\n", + "\n", + " # print(seq_meas.shape)\n", + " # coupled_meas.append({'copies': copies, 'threads': threads, 'values': meas['step_time'].data})\n", + " decoupled_mean.append(\n", + " {\"copies\": copies, \"threads\": threads, \"values\": seq_meas.mean()}\n", + " )\n", + " decoupled_max.append(\n", + " {\"copies\": copies, \"threads\": threads, \"values\": seq_meas.max()}\n", + " )\n", + " decoupled_std.append(\n", + " {\"copies\": copies, \"threads\": threads, \"values\": seq_meas.std()}\n", + " )\n", + "\n", "pd_decoupled_meas = pd.DataFrame(decoupled_meas)\n", "pd_decoupled_mean = pd.DataFrame(decoupled_mean)\n", "pd_decoupled_max = pd.DataFrame(decoupled_max)\n", @@ -336,19 +419,24 @@ "\n", "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(2))\n", - "copies = np.arange(1,21)\n", + "copies = np.arange(1, 21)\n", "\n", - "for threads in range(0,13,2): \n", - " plt.plot(copies, pd_decoupled_mean.query('threads=='+str(threads))['values'].values, label=str(threads)+' threads', marker='o')\n", + "for threads in range(0, 13, 2):\n", + " plt.plot(\n", + " copies,\n", + " pd_decoupled_mean.query(\"threads==\" + str(threads))[\"values\"].values,\n", + " label=str(threads) + \" threads\",\n", + " marker=\"o\",\n", + " )\n", "\n", - "#plt.ylim([0,0.00025])\n", + "# plt.ylim([0,0.00025])\n", "\n", - "plt.xlabel('number of system copies')\n", - "plt.ylabel('mean timestep duration (s)')\n", + "plt.xlabel(\"number of system copies\")\n", + "plt.ylabel(\"mean timestep duration (s)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('9bus_decoupled.pdf')" + "plt.savefig(\"9bus_decoupled.pdf\")" ] }, { @@ -357,36 +445,76 @@ "metadata": {}, "outputs": [], "source": [ - "#%%capture\n", - "from dpsim.MeasurementUtils import Measurement \n", + "# %%capture\n", + "from dpsim.MeasurementUtils import Measurement\n", "import numpy as np\n", "import pandas as pd\n", "\n", - "logs_dir = '../../../logs_9bus/'\n", + "logs_dir = \"../../../logs_9bus/\"\n", "diakoptics_meas = []\n", "diakoptics_mean = []\n", "diakoptics_max = []\n", "diakoptics_std = []\n", - " \n", - "for copies in range(0,20): \n", - " for threads in range(0,13,2): \n", - " for splits in range(0, copies+2):\n", + "\n", + "for copies in range(0, 20):\n", + " for threads in range(0, 13, 2):\n", + " for splits in range(0, copies + 2):\n", " seq_meas = []\n", - " for seq in range(1,11):\n", - " log_path = logs_dir + 'WSCC_9bus_diakoptics_' + str(copies) + '_' + str(threads) + '_' + str(splits) + '_' + str(seq) + '/' + \\\n", - " 'WSCC_9bus_diakoptics_' + str(copies) + '_' + str(threads) + '_' + str(splits) + '_' + str(seq) + '_step_times.log' \n", - " #print(log_path)\n", - " meas = Measurement.read_timestep_csv(log_path)['step_time'].data\n", + " for seq in range(1, 11):\n", + " log_path = (\n", + " logs_dir\n", + " + \"WSCC_9bus_diakoptics_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(splits)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"/\"\n", + " + \"WSCC_9bus_diakoptics_\"\n", + " + str(copies)\n", + " + \"_\"\n", + " + str(threads)\n", + " + \"_\"\n", + " + str(splits)\n", + " + \"_\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", + " # print(log_path)\n", + " meas = Measurement.read_timestep_csv(log_path)[\"step_time\"].data\n", " # aggregate the measurements from the different iterations\n", - " seq_meas = np.concatenate( (seq_meas, meas), axis=0)\n", - "\n", - " #print(seq_meas.shape)\n", - " #diakoptics_meas.append({'copies': copies, 'threads': threads, 'splits': splits, 'values': meas['step_time'].data}) \n", - " diakoptics_mean.append({'copies': copies, 'threads': threads, 'splits': splits, 'values': seq_meas.mean()}) \n", - " diakoptics_max.append({'copies': copies, 'threads': threads, 'splits': splits, 'values': seq_meas.max()}) \n", - " diakoptics_std.append({'copies': copies, 'threads': threads, 'splits': splits, 'values': seq_meas.std()}) \n", - " \n", - "#pd_diakoptics_meas = pd.DataFrame(diakoptics_meas)\n", + " seq_meas = np.concatenate((seq_meas, meas), axis=0)\n", + "\n", + " # print(seq_meas.shape)\n", + " # diakoptics_meas.append({'copies': copies, 'threads': threads, 'splits': splits, 'values': meas['step_time'].data})\n", + " diakoptics_mean.append(\n", + " {\n", + " \"copies\": copies,\n", + " \"threads\": threads,\n", + " \"splits\": splits,\n", + " \"values\": seq_meas.mean(),\n", + " }\n", + " )\n", + " diakoptics_max.append(\n", + " {\n", + " \"copies\": copies,\n", + " \"threads\": threads,\n", + " \"splits\": splits,\n", + " \"values\": seq_meas.max(),\n", + " }\n", + " )\n", + " diakoptics_std.append(\n", + " {\n", + " \"copies\": copies,\n", + " \"threads\": threads,\n", + " \"splits\": splits,\n", + " \"values\": seq_meas.std(),\n", + " }\n", + " )\n", + "\n", + "# pd_diakoptics_meas = pd.DataFrame(diakoptics_meas)\n", "pd_diakoptics_mean = pd.DataFrame(diakoptics_mean)\n", "pd_diakoptics_max = pd.DataFrame(diakoptics_max)\n", "pd_diakoptics_std = pd.DataFrame(diakoptics_std)" @@ -399,18 +527,39 @@ "outputs": [], "source": [ "diakoptics_mean_split_min = []\n", - "for copies in range(0,20): \n", - " for threads in range(0,13,2): \n", - " split_min_num = copies+1\n", - " split_min = pd_diakoptics_mean.query('copies=='+str(copies)+' and threads=='+str(threads)+' and splits=='+str(split_min_num))['values'].iloc[0]\n", - " for splits in range(1, copies+1):\n", - " tmp = pd_diakoptics_mean.query('copies=='+str(copies)+' and threads=='+str(threads)+' and splits=='+str(splits))['values'].iloc[0]\n", + "for copies in range(0, 20):\n", + " for threads in range(0, 13, 2):\n", + " split_min_num = copies + 1\n", + " split_min = pd_diakoptics_mean.query(\n", + " \"copies==\"\n", + " + str(copies)\n", + " + \" and threads==\"\n", + " + str(threads)\n", + " + \" and splits==\"\n", + " + str(split_min_num)\n", + " )[\"values\"].iloc[0]\n", + " for splits in range(1, copies + 1):\n", + " tmp = pd_diakoptics_mean.query(\n", + " \"copies==\"\n", + " + str(copies)\n", + " + \" and threads==\"\n", + " + str(threads)\n", + " + \" and splits==\"\n", + " + str(splits)\n", + " )[\"values\"].iloc[0]\n", " if tmp < split_min:\n", " split_min_num = splits\n", " split_min = tmp\n", - " \n", - " diakoptics_mean_split_min.append({'copies': copies, 'threads': threads, 'splits': split_min_num, 'values': split_min}) \n", - " \n", + "\n", + " diakoptics_mean_split_min.append(\n", + " {\n", + " \"copies\": copies,\n", + " \"threads\": threads,\n", + " \"splits\": split_min_num,\n", + " \"values\": split_min,\n", + " }\n", + " )\n", + "\n", "pd_diakoptics_mean_split_min = pd.DataFrame(diakoptics_mean_split_min)" ] }, @@ -420,7 +569,7 @@ "metadata": {}, "outputs": [], "source": [ - "pd_diakoptics_mean_split_min.query('threads=='+str(8))" + "pd_diakoptics_mean_split_min.query(\"threads==\" + str(8))" ] }, { @@ -431,9 +580,13 @@ "source": [ "diakoptics_splits = []\n", "\n", - "for copies in range(0,20): \n", - " for threads in range(0,13,2):\n", - " diakoptics_splits.append(pd_diakoptics_mean_split_min.query('copies=='+str(copies)+' and threads=='+str(threads))['splits'].values)" + "for copies in range(0, 20):\n", + " for threads in range(0, 13, 2):\n", + " diakoptics_splits.append(\n", + " pd_diakoptics_mean_split_min.query(\n", + " \"copies==\" + str(copies) + \" and threads==\" + str(threads)\n", + " )[\"splits\"].values\n", + " )" ] }, { @@ -446,18 +599,23 @@ "\n", "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(2))\n", - "copies = np.arange(1,21)\n", + "copies = np.arange(1, 21)\n", "\n", - "for threads in range(0,13,2):\n", - " plt.plot(copies, pd_diakoptics_mean_split_min.query('threads=='+str(threads))['splits'].values, label= str(threads) + ' threads', marker='o')\n", + "for threads in range(0, 13, 2):\n", + " plt.plot(\n", + " copies,\n", + " pd_diakoptics_mean_split_min.query(\"threads==\" + str(threads))[\"splits\"].values,\n", + " label=str(threads) + \" threads\",\n", + " marker=\"o\",\n", + " )\n", "\n", "\n", - "plt.xlabel('number of system copies')\n", - "plt.ylabel('mean split number')\n", + "plt.xlabel(\"number of system copies\")\n", + "plt.ylabel(\"mean split number\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('diakoptics_min_mean_splits.pdf')" + "plt.savefig(\"diakoptics_min_mean_splits.pdf\")" ] }, { @@ -470,17 +628,22 @@ "\n", "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(2))\n", - "copies = np.arange(1,21)\n", - "\n", - "for threads in range(0,13,2):\n", - " plt.plot(copies, pd_diakoptics_mean_split_min.query('threads=='+str(threads))['values'].values, label= str(threads) + ' threads', marker='o')\n", - "\n", - "plt.xlabel('number of system copies')\n", - "plt.ylabel('mean timestep duration (s)')\n", + "copies = np.arange(1, 21)\n", + "\n", + "for threads in range(0, 13, 2):\n", + " plt.plot(\n", + " copies,\n", + " pd_diakoptics_mean_split_min.query(\"threads==\" + str(threads))[\"values\"].values,\n", + " label=str(threads) + \" threads\",\n", + " marker=\"o\",\n", + " )\n", + "\n", + "plt.xlabel(\"number of system copies\")\n", + "plt.ylabel(\"mean timestep duration (s)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('9bus_diakoptics.pdf')" + "plt.savefig(\"9bus_diakoptics.pdf\")" ] }, { @@ -493,21 +656,36 @@ "\n", "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(2))\n", - "copies = np.arange(1,21)\n", + "copies = np.arange(1, 21)\n", "threads = 8\n", "\n", - "plt.plot(copies, pd_coupled_mean.query('threads=='+str(threads))['values'].values, label='coupled, 8 threads', marker='o')\n", - "plt.plot(copies, pd_decoupled_mean.query('threads=='+str(threads))['values'].values, label='line decoupled, 8 threads', marker='o')\n", - "plt.plot(copies, pd_diakoptics_mean_split_min.query('threads=='+str(threads))['values'].values, label='diakoptics, 8 threads', marker='o')\n", - "\n", - "plt.xlabel('number of system copies')\n", - "plt.ylabel('mean timestep duration (s)')\n", + "plt.plot(\n", + " copies,\n", + " pd_coupled_mean.query(\"threads==\" + str(threads))[\"values\"].values,\n", + " label=\"coupled, 8 threads\",\n", + " marker=\"o\",\n", + ")\n", + "plt.plot(\n", + " copies,\n", + " pd_decoupled_mean.query(\"threads==\" + str(threads))[\"values\"].values,\n", + " label=\"line decoupled, 8 threads\",\n", + " marker=\"o\",\n", + ")\n", + "plt.plot(\n", + " copies,\n", + " pd_diakoptics_mean_split_min.query(\"threads==\" + str(threads))[\"values\"].values,\n", + " label=\"diakoptics, 8 threads\",\n", + " marker=\"o\",\n", + ")\n", + "\n", + "plt.xlabel(\"number of system copies\")\n", + "plt.ylabel(\"mean timestep duration (s)\")\n", "plt.grid()\n", "plt.legend()\n", - "plt.yscale('log')\n", + "plt.yscale(\"log\")\n", "plt.tight_layout()\n", - "plt.savefig('9bus_comparison.pdf')\n", - "plt.savefig('9bus_comparison.png', dpi=300)" + "plt.savefig(\"9bus_comparison.pdf\")\n", + "plt.savefig(\"9bus_comparison.png\", dpi=300)" ] }, { diff --git a/examples/Notebooks/Performance/WSCC_9bus_split.ipynb b/examples/Notebooks/Performance/WSCC_9bus_split.ipynb index de3af0b793..95bcf3e694 100644 --- a/examples/Notebooks/Performance/WSCC_9bus_split.ipynb +++ b/examples/Notebooks/Performance/WSCC_9bus_split.ipynb @@ -68,7 +68,8 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", - "#%matplotlib widget" + "\n", + "# %matplotlib widget" ] }, { @@ -77,24 +78,24 @@ "metadata": {}, "outputs": [], "source": [ - "path_split_dp = 'logs/WSCC_9bus_split_decoupled_DP_0_0/'\n", - "logName_split_dp = 'WSCC_9bus_split_decoupled_DP_0_0'\n", - "logFilename_split_dp = path_split_dp + logName_split_dp + '.csv'\n", + "path_split_dp = \"logs/WSCC_9bus_split_decoupled_DP_0_0/\"\n", + "logName_split_dp = \"WSCC_9bus_split_decoupled_DP_0_0\"\n", + "logFilename_split_dp = path_split_dp + logName_split_dp + \".csv\"\n", "print(logFilename_split_dp)\n", "\n", - "path_split_emt = 'logs/WSCC_9bus_split_decoupled_EMT_0_0/'\n", - "logName_split_emt = 'WSCC_9bus_split_decoupled_EMT_0_0'\n", - "logFilename_split_emt = path_split_emt + logName_split_emt + '.csv'\n", + "path_split_emt = \"logs/WSCC_9bus_split_decoupled_EMT_0_0/\"\n", + "logName_split_emt = \"WSCC_9bus_split_decoupled_EMT_0_0\"\n", + "logFilename_split_emt = path_split_emt + logName_split_emt + \".csv\"\n", "print(logFilename_split_emt)\n", "\n", - "path_mono_dp = 'logs/WSCC-9bus_monolithic_DP/'\n", - "logName_mono_dp = 'WSCC-9bus_monolithic_DP'\n", - "logFilename_mono_dp = path_mono_dp + logName_mono_dp + '.csv'\n", + "path_mono_dp = \"logs/WSCC-9bus_monolithic_DP/\"\n", + "logName_mono_dp = \"WSCC-9bus_monolithic_DP\"\n", + "logFilename_mono_dp = path_mono_dp + logName_mono_dp + \".csv\"\n", "print(logFilename_mono_dp)\n", "\n", - "path_mono_emt = 'logs/WSCC-9bus_monolithic_EMT/'\n", - "logName_mono_emt = 'WSCC-9bus_monolithic_EMT'\n", - "logFilename_mono_emt = path_mono_emt + logName_mono_emt + '.csv'\n", + "path_mono_emt = \"logs/WSCC-9bus_monolithic_EMT/\"\n", + "logName_mono_emt = \"WSCC-9bus_monolithic_EMT\"\n", + "logFilename_mono_emt = path_mono_emt + logName_mono_emt + \".csv\"\n", "print(logFilename_mono_emt)\n", "\n", "decoupled_dp_split = rt.read_timeseries_dpsim(logFilename_split_dp)\n", @@ -104,14 +105,14 @@ "\n", "# for v in range(1, 10):\n", "for i, v in enumerate([5]):\n", - " varname = 'v' + str(v)\n", - " pt.set_timeseries_labels(mono_dp[varname], varname + ' Monolithic, DP')\n", - " pt.plot_timeseries('decoupled', mono_dp[varname])\n", - " pt.set_timeseries_labels(decoupled_dp_split[varname], varname + ' DP')\n", - " pt.plot_timeseries('decoupled', decoupled_dp_split[varname], '--')\n", - " plt.title('WSCC-09 with 3 lines replaced by decoupling equivalents')\n", - " plt.xlabel('Time [s]')\n", - " plt.ylabel('Voltage [V]')\n", + " varname = \"v\" + str(v)\n", + " pt.set_timeseries_labels(mono_dp[varname], varname + \" Monolithic, DP\")\n", + " pt.plot_timeseries(\"decoupled\", mono_dp[varname])\n", + " pt.set_timeseries_labels(decoupled_dp_split[varname], varname + \" DP\")\n", + " pt.plot_timeseries(\"decoupled\", decoupled_dp_split[varname], \"--\")\n", + " plt.title(\"WSCC-09 with 3 lines replaced by decoupling equivalents\")\n", + " plt.xlabel(\"Time [s]\")\n", + " plt.ylabel(\"Voltage [V]\")\n", "\n", "plt.show()" ] @@ -125,14 +126,14 @@ "decoupled_emt_split = rt.read_timeseries_dpsim(logFilename_split_emt)\n", "\n", "for i, v in enumerate([5]):\n", - " varname_emt = 'v' + str(v) + '_0'\n", - " pt.set_timeseries_labels(mono_emt[varname_emt], varname_emt + ' Monolithic, EMT')\n", - " pt.plot_timeseries('decoupled, shifted', mono_emt[varname_emt])\n", - " pt.set_timeseries_labels(decoupled_emt_split[varname_emt], varname_emt + ' EMT')\n", - " pt.plot_timeseries('decoupled, shifted', decoupled_emt_split[varname_emt], '--')\n", - " plt.title('WSCC-09 with 3 lines replaced by decoupling equivalents')\n", - " plt.xlabel('Time [s]')\n", - " plt.ylabel('Voltage [V]')\n", + " varname_emt = \"v\" + str(v) + \"_0\"\n", + " pt.set_timeseries_labels(mono_emt[varname_emt], varname_emt + \" Monolithic, EMT\")\n", + " pt.plot_timeseries(\"decoupled, shifted\", mono_emt[varname_emt])\n", + " pt.set_timeseries_labels(decoupled_emt_split[varname_emt], varname_emt + \" EMT\")\n", + " pt.plot_timeseries(\"decoupled, shifted\", decoupled_emt_split[varname_emt], \"--\")\n", + " plt.title(\"WSCC-09 with 3 lines replaced by decoupling equivalents\")\n", + " plt.xlabel(\"Time [s]\")\n", + " plt.ylabel(\"Voltage [V]\")\n", "\n", "plt.show()" ] diff --git a/examples/Notebooks/Performance/multimachine_parallel.ipynb b/examples/Notebooks/Performance/multimachine_parallel.ipynb index 5123fa2f6f..3dd55de770 100644 --- a/examples/Notebooks/Performance/multimachine_parallel.ipynb +++ b/examples/Notebooks/Performance/multimachine_parallel.ipynb @@ -39,29 +39,44 @@ "metadata": {}, "outputs": [], "source": [ - "logs_dir = '../../../logs_multimachine/'\n", + "logs_dir = \"../../../logs_multimachine/\"\n", "gen_mean = []\n", "gen_max = []\n", "gen_std = []\n", "\n", - "for gens in range(1,21): \n", - " for threads in range(0,13,2): \n", + "for gens in range(1, 21):\n", + " for threads in range(0, 13, 2):\n", " seq_meas = []\n", - " for seq in range(1,51):\n", - " log_path = logs_dir + 'DP_Multimachine_th' + str(threads) + '_gen' + str(gens) + '_rep' + str(seq) + '/' \\\n", - " + 'DP_Multimachine_th' + str(threads) + '_gen' + str(gens) + '_rep' + str(seq) + '_step_times.log' \n", - " #print(log_path)\n", - " meas = Measurement.read_timestep_csv(log_path)['step_time'].data\n", + " for seq in range(1, 51):\n", + " log_path = (\n", + " logs_dir\n", + " + \"DP_Multimachine_th\"\n", + " + str(threads)\n", + " + \"_gen\"\n", + " + str(gens)\n", + " + \"_rep\"\n", + " + str(seq)\n", + " + \"/\"\n", + " + \"DP_Multimachine_th\"\n", + " + str(threads)\n", + " + \"_gen\"\n", + " + str(gens)\n", + " + \"_rep\"\n", + " + str(seq)\n", + " + \"_step_times.log\"\n", + " )\n", + " # print(log_path)\n", + " meas = Measurement.read_timestep_csv(log_path)[\"step_time\"].data\n", " # aggregate the measurements from the different iterations\n", - " seq_meas = np.concatenate( (seq_meas, meas), axis=0)\n", - " \n", - " #print(seq_meas.shape)\n", - " #coupled_meas.append({'copies': copies, 'threads': threads, 'values': meas['step_time'].data}) \n", - " gen_mean.append({'copies': gens, 'threads': threads, 'values': seq_meas.mean()}) \n", - " gen_max.append({'copies': gens, 'threads': threads, 'values': seq_meas.max()}) \n", - " gen_std.append({'copies': gens, 'threads': threads, 'values': seq_meas.std()}) \n", - " \n", - "#pd_coupled_meas = pd.DataFrame(coupled_meas)\n", + " seq_meas = np.concatenate((seq_meas, meas), axis=0)\n", + "\n", + " # print(seq_meas.shape)\n", + " # coupled_meas.append({'copies': copies, 'threads': threads, 'values': meas['step_time'].data})\n", + " gen_mean.append({\"copies\": gens, \"threads\": threads, \"values\": seq_meas.mean()})\n", + " gen_max.append({\"copies\": gens, \"threads\": threads, \"values\": seq_meas.max()})\n", + " gen_std.append({\"copies\": gens, \"threads\": threads, \"values\": seq_meas.std()})\n", + "\n", + "# pd_coupled_meas = pd.DataFrame(coupled_meas)\n", "pd_gen_mean = pd.DataFrame(gen_mean)\n", "pd_gen_max = pd.DataFrame(gen_max)\n", "pd_gen_std = pd.DataFrame(gen_std)" @@ -87,22 +102,47 @@ "ax = plt.figure().gca()\n", "ax.xaxis.set_major_locator(ticker.MultipleLocator(2))\n", "\n", - "xaxis = np.arange(1,21)\n", - "plt.plot(xaxis, pd_gen_mean.query('threads=='+str(0))['values'].values*1e3, label=str(0)+' threads', marker='o')\n", - "plt.plot(xaxis, pd_gen_mean.query('threads=='+str(2))['values'].values*1e3, label=str(2)+' threads', marker='o')\n", - "plt.plot(xaxis, pd_gen_mean.query('threads=='+str(4))['values'].values*1e3, label=str(4)+' threads', marker='o')\n", - "plt.plot(xaxis, pd_gen_mean.query('threads=='+str(8))['values'].values*1e3, label=str(8)+' threads', marker='o')\n", - "plt.plot(xaxis, pd_gen_mean.query('threads=='+str(12))['values'].values*1e3, label=str(12)+' threads', marker='o')\n", + "xaxis = np.arange(1, 21)\n", + "plt.plot(\n", + " xaxis,\n", + " pd_gen_mean.query(\"threads==\" + str(0))[\"values\"].values * 1e3,\n", + " label=str(0) + \" threads\",\n", + " marker=\"o\",\n", + ")\n", + "plt.plot(\n", + " xaxis,\n", + " pd_gen_mean.query(\"threads==\" + str(2))[\"values\"].values * 1e3,\n", + " label=str(2) + \" threads\",\n", + " marker=\"o\",\n", + ")\n", + "plt.plot(\n", + " xaxis,\n", + " pd_gen_mean.query(\"threads==\" + str(4))[\"values\"].values * 1e3,\n", + " label=str(4) + \" threads\",\n", + " marker=\"o\",\n", + ")\n", + "plt.plot(\n", + " xaxis,\n", + " pd_gen_mean.query(\"threads==\" + str(8))[\"values\"].values * 1e3,\n", + " label=str(8) + \" threads\",\n", + " marker=\"o\",\n", + ")\n", + "plt.plot(\n", + " xaxis,\n", + " pd_gen_mean.query(\"threads==\" + str(12))[\"values\"].values * 1e3,\n", + " label=str(12) + \" threads\",\n", + " marker=\"o\",\n", + ")\n", "\n", - "#plt.ylim([0,0.0004])\n", + "# plt.ylim([0,0.0004])\n", "\n", - "plt.xlabel('number of system copies')\n", - "plt.ylabel('mean timestep duration (ms)')\n", + "plt.xlabel(\"number of system copies\")\n", + "plt.ylabel(\"mean timestep duration (ms)\")\n", "plt.grid()\n", "plt.legend()\n", "plt.tight_layout()\n", - "plt.savefig('multimachine_parallel.pdf')\n", - "plt.savefig('multimachine_parallel.png', dpi=300)" + "plt.savefig(\"multimachine_parallel.pdf\")\n", + "plt.savefig(\"multimachine_parallel.png\", dpi=300)" ] }, { diff --git a/examples/Notebooks/Quickstart Guide.ipynb b/examples/Notebooks/Quickstart Guide.ipynb index bd10f81080..59b2c24b7a 100644 --- a/examples/Notebooks/Quickstart Guide.ipynb +++ b/examples/Notebooks/Quickstart Guide.ipynb @@ -56,12 +56,12 @@ "source": [ "# Nodes\n", "gnd = dpsimpy.dp.SimNode.gnd\n", - "n0 = dpsimpy.dp.SimNode(\"n0\")\n", - "n1 = dpsimpy.dp.SimNode(\"n1\")\n", - "n2 = dpsimpy.dp.SimNode(\"n2\")\n", + "n0 = dpsimpy.dp.SimNode(\"n0\")\n", + "n1 = dpsimpy.dp.SimNode(\"n1\")\n", + "n2 = dpsimpy.dp.SimNode(\"n2\")\n", "\n", "v_s = dpsimpy.dp.ph1.VoltageSource(\"v_s\")\n", - "v_s.V_ref = 10000+0j\n", + "v_s.V_ref = 10000 + 0j\n", "r_line = dpsimpy.dp.ph1.Resistor(\"r_line\")\n", "r_line.R = 1\n", "l_line = dpsimpy.dp.ph1.Inductor(\"l_line\")\n", @@ -69,7 +69,7 @@ "r_load = dpsimpy.dp.ph1.Resistor(\"r_load\")\n", "r_load.R = 1000\n", "\n", - "# Connections \n", + "# Connections\n", "v_s.connect([n0, gnd])\n", "r_line.connect([n0, n1])\n", "l_line.connect([n1, n2])\n", @@ -89,7 +89,7 @@ "metadata": {}, "outputs": [], "source": [ - "sys = dpsimpy.SystemTopology(50, [ n0, n1, n2 ], [ v_s, r_line, l_line, r_load ])" + "sys = dpsimpy.SystemTopology(50, [n0, n1, n2], [v_s, r_line, l_line, r_load])" ] }, { @@ -131,7 +131,7 @@ " log.log_attribute(\"v\" + str(i), \"v\", sys.nodes[i])\n", "\n", "sim.add_logger(log)\n", - " \n", + "\n", "sim.run()" ] }, @@ -157,11 +157,11 @@ "import villas.dataprocessing.readtools as rt\n", "import villas.dataprocessing.timeseries as ts\n", "\n", - "results = rt.read_timeseries_dpsim('logs/Example1.csv')\n", - "results_emt = [ results[series].frequency_shift(freq=50) for series in results ]\n", + "results = rt.read_timeseries_dpsim(\"logs/Example1.csv\")\n", + "results_emt = [results[series].frequency_shift(freq=50) for series in results]\n", "\n", "for series in results_emt:\n", - " pt.plot_timeseries('Results EMT', series)\n", + " pt.plot_timeseries(\"Results EMT\", series)\n", "\n", "plt.show()" ] diff --git a/examples/Notebooks/Understanding_DP.ipynb b/examples/Notebooks/Understanding_DP.ipynb index 3fc1624c78..dfee8051a9 100644 --- a/examples/Notebooks/Understanding_DP.ipynb +++ b/examples/Notebooks/Understanding_DP.ipynb @@ -72,11 +72,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_VS_RL_f60/'\n", - "log_name = 'DP_VS_RL_f60'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_VS_RL_f60/\"\n", + "log_name = \"DP_VS_RL_f60\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp_f60 = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp_f60 = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_dp_f60_emt = ts.frequency_shift_list(ts_dpsim_dp_f60, 50)" ] }, @@ -87,11 +87,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/EMT_VS_RL_f60/'\n", - "log_name = 'EMT_VS_RL_f60'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/EMT_VS_RL_f60/\"\n", + "log_name = \"EMT_VS_RL_f60\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_emt_f60 = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "ts_dpsim_emt_f60 = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -100,35 +100,77 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_emt_f60['v1'].time, ts_dpsim_emt_f60['v1'].values, color='#939393ff', label='v1 emt')\n", - "plt.plot(ts_dpsim_emt_f60['v3'].time, ts_dpsim_emt_f60['v3'].values, color='#939393ff', label='v3 emt')\n", - "plt.plot(ts_dpsim_dp_f60_emt['v1_shift'].time, ts_dpsim_dp_f60_emt['v1_shift'].values, linestyle='-.', label='v1 dp')\n", - "plt.plot(ts_dpsim_dp_f60_emt['v3_shift'].time, ts_dpsim_dp_f60_emt['v3_shift'].values, linestyle='-.', label='v3 dp')\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (v)')\n", - "plt.title('DP 50Hz shift (100µs ts) vs EMT (100µs ts), 60Hz source')\n", - "plt.savefig('emt_dp_100mics_60Hz_src.pdf')\n", + "plt.plot(\n", + " ts_dpsim_emt_f60[\"v1\"].time,\n", + " ts_dpsim_emt_f60[\"v1\"].values,\n", + " color=\"#939393ff\",\n", + " label=\"v1 emt\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_f60[\"v3\"].time,\n", + " ts_dpsim_emt_f60[\"v3\"].values,\n", + " color=\"#939393ff\",\n", + " label=\"v3 emt\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_emt[\"v1_shift\"].time,\n", + " ts_dpsim_dp_f60_emt[\"v1_shift\"].values,\n", + " linestyle=\"-.\",\n", + " label=\"v1 dp\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_emt[\"v3_shift\"].time,\n", + " ts_dpsim_dp_f60_emt[\"v3_shift\"].values,\n", + " linestyle=\"-.\",\n", + " label=\"v3 dp\",\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (v)\")\n", + "plt.title(\"DP 50Hz shift (100µs ts) vs EMT (100µs ts), 60Hz source\")\n", + "plt.savefig(\"emt_dp_100mics_60Hz_src.pdf\")\n", "\n", "ts_dpsim_dp_f60_phasors = ts.phasors(ts_dpsim_dp_f60)\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f60_phasors['v1']['phase'].time, ts_dpsim_dp_f60_phasors['v1']['phase'].values, label='v1 dp')\n", - "plt.plot(ts_dpsim_dp_f60_phasors['v3']['phase'].time, ts_dpsim_dp_f60_phasors['v3']['phase'].values, label='v3 dp')\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.title('DP 50Hz shift (100µs ts), 60Hz source')\n", - "plt.savefig('emt_dp_100mics_60Hz_src_phase.pdf')\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_phasors[\"v1\"][\"phase\"].time,\n", + " ts_dpsim_dp_f60_phasors[\"v1\"][\"phase\"].values,\n", + " label=\"v1 dp\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_phasors[\"v3\"][\"phase\"].time,\n", + " ts_dpsim_dp_f60_phasors[\"v3\"][\"phase\"].values,\n", + " label=\"v3 dp\",\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.title(\"DP 50Hz shift (100µs ts), 60Hz source\")\n", + "plt.savefig(\"emt_dp_100mics_60Hz_src_phase.pdf\")\n", "\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f60_emt['v1_shift'].time, ts_dpsim_dp_f60_emt['v1_shift'].values, linestyle='-.')\n", - "plt.plot(ts_dpsim_dp_f60_emt['v3_shift'].time, ts_dpsim_dp_f60_emt['v3_shift'].values, linestyle='-.')\n", - "plt.plot(ts_dpsim_dp_f60_phasors['v1']['abs'].time, ts_dpsim_dp_f60_phasors['v1']['abs'].values)\n", - "plt.plot(ts_dpsim_dp_f60_phasors['v3']['abs'].time, ts_dpsim_dp_f60_phasors['v3']['abs'].values)\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('votlage (V)')\n", - "plt.title('DP 50Hz shift (100µs ts), 60Hz source')" + "plt.plot(\n", + " ts_dpsim_dp_f60_emt[\"v1_shift\"].time,\n", + " ts_dpsim_dp_f60_emt[\"v1_shift\"].values,\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_emt[\"v3_shift\"].time,\n", + " ts_dpsim_dp_f60_emt[\"v3_shift\"].values,\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_phasors[\"v1\"][\"abs\"].time,\n", + " ts_dpsim_dp_f60_phasors[\"v1\"][\"abs\"].values,\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_phasors[\"v3\"][\"abs\"].time,\n", + " ts_dpsim_dp_f60_phasors[\"v3\"][\"abs\"].values,\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"votlage (V)\")\n", + "plt.title(\"DP 50Hz shift (100µs ts), 60Hz source\")" ] }, { @@ -170,11 +212,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_VS_RL_f60_largeTs/'\n", - "log_name = 'DP_VS_RL_f60_largeTs'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_VS_RL_f60_largeTs/\"\n", + "log_name = \"DP_VS_RL_f60_largeTs\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp_f60_lTs = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp_f60_lTs = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_dp_f60_lTs_intp = ts.interpolate_cmpl_list(ts_dpsim_dp_f60_lTs, 0.0001)\n", "ts_dpsim_dp_f60_lTs_intp_emt = ts.frequency_shift_list(ts_dpsim_dp_f60_lTs_intp, 50)" ] @@ -186,11 +228,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/EMT_VS_RL_f60_largeTs/'\n", - "log_name = 'EMT_VS_RL_f60_largeTs'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/EMT_VS_RL_f60_largeTs/\"\n", + "log_name = \"EMT_VS_RL_f60_largeTs\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_emt_f60_lTs = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_emt_f60_lTs = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_emt_f60_lTs_intp = ts.interpolate_cmpl_list(ts_dpsim_emt_f60_lTs, 0.0001)" ] }, @@ -200,23 +242,42 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_emt_f60['v3'].time, ts_dpsim_emt_f60['v3'].values, label='v3 emt 100µs', color = '#939393ff')\n", - "plt.plot(ts_dpsim_dp_f60_lTs_intp_emt['v3_intpl_shift'].time, ts_dpsim_dp_f60_lTs_intp_emt['v3_intpl_shift'].values, label='v3 dp 10ms', linestyle='-.') \n", - "plt.plot(ts_dpsim_emt_f60_lTs_intp['v3_intpl'].time, ts_dpsim_emt_f60_lTs_intp['v3_intpl'].values, label='v3 emt 10ms', linestyle=':')\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (v)')\n", - "plt.title('DP 50Hz shift (10ms ts) vs EMT (10ms ts), 60Hz source')\n", - "plt.legend(loc='lower right')\n", - "plt.savefig('emt_dp_10ms_60Hz_src.pdf')\n", + "plt.plot(\n", + " ts_dpsim_emt_f60[\"v3\"].time,\n", + " ts_dpsim_emt_f60[\"v3\"].values,\n", + " label=\"v3 emt 100µs\",\n", + " color=\"#939393ff\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_lTs_intp_emt[\"v3_intpl_shift\"].time,\n", + " ts_dpsim_dp_f60_lTs_intp_emt[\"v3_intpl_shift\"].values,\n", + " label=\"v3 dp 10ms\",\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_f60_lTs_intp[\"v3_intpl\"].time,\n", + " ts_dpsim_emt_f60_lTs_intp[\"v3_intpl\"].values,\n", + " label=\"v3 emt 10ms\",\n", + " linestyle=\":\",\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (v)\")\n", + "plt.title(\"DP 50Hz shift (10ms ts) vs EMT (10ms ts), 60Hz source\")\n", + "plt.legend(loc=\"lower right\")\n", + "plt.savefig(\"emt_dp_10ms_60Hz_src.pdf\")\n", "\n", "ts_dpsim_dp_f60_lTs_phasors = ts.phasors(ts_dpsim_dp_f60_lTs_intp)\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f60_lTs_phasors['v3_intpl']['phase'].time, ts_dpsim_dp_f60_lTs_phasors['v3_intpl']['phase'].values, label='v3 dp 10ms')\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.title('DP 50Hz shift (10ms ts), 60Hz source')" + "plt.plot(\n", + " ts_dpsim_dp_f60_lTs_phasors[\"v3_intpl\"][\"phase\"].time,\n", + " ts_dpsim_dp_f60_lTs_phasors[\"v3_intpl\"][\"phase\"].values,\n", + " label=\"v3 dp 10ms\",\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.title(\"DP 50Hz shift (10ms ts), 60Hz source\")" ] }, { @@ -290,11 +351,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_VS_RL_f60_vlargeTs/'\n", - "log_name = 'DP_VS_RL_f60_vlargeTs'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_VS_RL_f60_vlargeTs/\"\n", + "log_name = \"DP_VS_RL_f60_vlargeTs\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp_f60_vlTs = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp_f60_vlTs = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_dp_f60_vlTs_intp = ts.interpolate_cmpl_list(ts_dpsim_dp_f60_vlTs, 0.0001)\n", "ts_dpsim_dp_f60_vlTs_intp_emt = ts.frequency_shift_list(ts_dpsim_dp_f60_vlTs_intp, 50)" ] @@ -305,23 +366,39 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_dp_f60_vlTs_intp_emt['v1_intpl_shift'].time, ts_dpsim_dp_f60_vlTs_intp_emt['v1_intpl_shift'].values, label='v1 dp intpl')\n", - "plt.plot(ts_dpsim_dp_f60_vlTs_intp_emt['v3_intpl_shift'].time, ts_dpsim_dp_f60_vlTs_intp_emt['v3_intpl_shift'].values, label='v3 dp intpl')\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (v)')\n", - "plt.title('DP 50Hz shift (50ms ts), 60Hz source')\n", - "plt.legend(loc='lower right')\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_vlTs_intp_emt[\"v1_intpl_shift\"].time,\n", + " ts_dpsim_dp_f60_vlTs_intp_emt[\"v1_intpl_shift\"].values,\n", + " label=\"v1 dp intpl\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_vlTs_intp_emt[\"v3_intpl_shift\"].time,\n", + " ts_dpsim_dp_f60_vlTs_intp_emt[\"v3_intpl_shift\"].values,\n", + " label=\"v3 dp intpl\",\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (v)\")\n", + "plt.title(\"DP 50Hz shift (50ms ts), 60Hz source\")\n", + "plt.legend(loc=\"lower right\")\n", "\n", "ts_dpsim_dp_f60_vlTs_phasors = ts.phasors(ts_dpsim_dp_f60_vlTs_intp)\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f60_vlTs_phasors['v1_intpl']['phase'].time, ts_dpsim_dp_f60_vlTs_phasors['v1_intpl']['phase'].values, label='v1 dp intpl')\n", - "plt.plot(ts_dpsim_dp_f60_vlTs_phasors['v3_intpl']['phase'].time, ts_dpsim_dp_f60_vlTs_phasors['v3_intpl']['phase'].values, label='v3 dp intpl')\n", - "plt.xlim([0,0.1])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.title('DP 50Hz shift (50ms ts), 60Hz source')\n", - "plt.legend(loc='lower right')" + "plt.plot(\n", + " ts_dpsim_dp_f60_vlTs_phasors[\"v1_intpl\"][\"phase\"].time,\n", + " ts_dpsim_dp_f60_vlTs_phasors[\"v1_intpl\"][\"phase\"].values,\n", + " label=\"v1 dp intpl\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f60_vlTs_phasors[\"v3_intpl\"][\"phase\"].time,\n", + " ts_dpsim_dp_f60_vlTs_phasors[\"v3_intpl\"][\"phase\"].values,\n", + " label=\"v3 dp intpl\",\n", + ")\n", + "plt.xlim([0, 0.1])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.title(\"DP 50Hz shift (50ms ts), 60Hz source\")\n", + "plt.legend(loc=\"lower right\")" ] }, { @@ -365,11 +442,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_VS_RL_f500/'\n", - "log_name = 'DP_VS_RL_f500'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_VS_RL_f500/\"\n", + "log_name = \"DP_VS_RL_f500\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp_f500 = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp_f500 = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_dp_f500_emt = ts.frequency_shift_list(ts_dpsim_dp_f500, 50)" ] }, @@ -380,11 +457,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/EMT_VS_RL_f500/'\n", - "log_name = 'EMT_VS_RL_f500'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/EMT_VS_RL_f500/\"\n", + "log_name = \"EMT_VS_RL_f500\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_emt_f500 = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')" + "ts_dpsim_emt_f500 = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")" ] }, { @@ -393,23 +470,51 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_emt_f500['v1'].time, ts_dpsim_emt_f500['v1'].values, label='v1 emt', color = '#939393ff')\n", - "plt.plot(ts_dpsim_emt_f500['v3'].time, ts_dpsim_emt_f500['v3'].values, label='v3 emt', color = '#939393ff')\n", - "plt.plot(ts_dpsim_dp_f500_emt['v1_shift'].time, ts_dpsim_dp_f500_emt['v1_shift'].values, label='v1 dp', linestyle='-.')\n", - "plt.plot(ts_dpsim_dp_f500_emt['v3_shift'].time, ts_dpsim_dp_f500_emt['v3_shift'].values, label='v3 dp', linestyle='-.')\n", - "plt.xlim([0,0.01])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (v)')\n", - "plt.title('DP 50Hz shift (10µs ts) vs EMT (10µs ts), 500Hz source')\n", + "plt.plot(\n", + " ts_dpsim_emt_f500[\"v1\"].time,\n", + " ts_dpsim_emt_f500[\"v1\"].values,\n", + " label=\"v1 emt\",\n", + " color=\"#939393ff\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_f500[\"v3\"].time,\n", + " ts_dpsim_emt_f500[\"v3\"].values,\n", + " label=\"v3 emt\",\n", + " color=\"#939393ff\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f500_emt[\"v1_shift\"].time,\n", + " ts_dpsim_dp_f500_emt[\"v1_shift\"].values,\n", + " label=\"v1 dp\",\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f500_emt[\"v3_shift\"].time,\n", + " ts_dpsim_dp_f500_emt[\"v3_shift\"].values,\n", + " label=\"v3 dp\",\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.xlim([0, 0.01])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (v)\")\n", + "plt.title(\"DP 50Hz shift (10µs ts) vs EMT (10µs ts), 500Hz source\")\n", "\n", "ts_dpsim_dp_f500_phasors = ts.phasors(ts_dpsim_dp_f500)\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f500_phasors['v1']['phase'].time, ts_dpsim_dp_f500_phasors['v1']['phase'].values, label='v1 dp')\n", - "plt.plot(ts_dpsim_dp_f500_phasors['v3']['phase'].time, ts_dpsim_dp_f500_phasors['v3']['phase'].values, label='v3 dp')\n", - "plt.xlim([0,0.01])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.title('DP 50Hz shift (10µs ts), 500Hz source')" + "plt.plot(\n", + " ts_dpsim_dp_f500_phasors[\"v1\"][\"phase\"].time,\n", + " ts_dpsim_dp_f500_phasors[\"v1\"][\"phase\"].values,\n", + " label=\"v1 dp\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f500_phasors[\"v3\"][\"phase\"].time,\n", + " ts_dpsim_dp_f500_phasors[\"v3\"][\"phase\"].values,\n", + " label=\"v3 dp\",\n", + ")\n", + "plt.xlim([0, 0.01])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.title(\"DP 50Hz shift (10µs ts), 500Hz source\")" ] }, { @@ -434,11 +539,11 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_VS_RL_f500_largeTs/'\n", - "log_name = 'DP_VS_RL_f500_largeTs'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_VS_RL_f500_largeTs/\"\n", + "log_name = \"DP_VS_RL_f500_largeTs\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp_f500_lTs = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp_f500_lTs = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_dp_f500_lTs_intp = ts.interpolate_cmpl_list(ts_dpsim_dp_f500_lTs, 0.00001)\n", "ts_dpsim_dp_f500_lTs_intp_emt = ts.frequency_shift_list(ts_dpsim_dp_f500_lTs_intp, 50)" ] @@ -449,19 +554,25 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_dp_f500_lTs_intp_emt['v1_intpl_shift'].time, ts_dpsim_dp_f500_lTs_intp_emt['v1_intpl_shift'].values)\n", - "plt.xlim([0,0.01])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (v)')\n", - "plt.title('DP 50Hz shift (2ms ts), 500Hz source')\n", + "plt.plot(\n", + " ts_dpsim_dp_f500_lTs_intp_emt[\"v1_intpl_shift\"].time,\n", + " ts_dpsim_dp_f500_lTs_intp_emt[\"v1_intpl_shift\"].values,\n", + ")\n", + "plt.xlim([0, 0.01])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (v)\")\n", + "plt.title(\"DP 50Hz shift (2ms ts), 500Hz source\")\n", "\n", "ts_dpsim_dp_f500_lTs_phasors = ts.phasors(ts_dpsim_dp_f500_lTs_intp)\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f500_lTs_phasors['v1_intpl']['phase'].time, ts_dpsim_dp_f500_lTs_phasors['v1_intpl']['phase'].values)\n", - "plt.xlim([0,0.01])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.title('DP 50Hz shift (2ms ts), 500Hz source')" + "plt.plot(\n", + " ts_dpsim_dp_f500_lTs_phasors[\"v1_intpl\"][\"phase\"].time,\n", + " ts_dpsim_dp_f500_lTs_phasors[\"v1_intpl\"][\"phase\"].values,\n", + ")\n", + "plt.xlim([0, 0.01])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.title(\"DP 50Hz shift (2ms ts), 500Hz source\")" ] }, { @@ -490,13 +601,15 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_VS_RL_f500_ph500/'\n", - "log_name = 'DP_VS_RL_f500_ph500'\n", - "print(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_VS_RL_f500_ph500/\"\n", + "log_name = \"DP_VS_RL_f500_ph500\"\n", + "print(work_dir + log_name + \".csv\")\n", "\n", - "ts_dpsim_dp_f500_ph500 = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "ts_dpsim_dp_f500_ph500 = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_dp_f500_ph500_intp = ts.interpolate_cmpl_list(ts_dpsim_dp_f500_ph500, 0.00001)\n", - "ts_dpsim_dp_f500_ph500_intp_emt = ts.frequency_shift_list(ts_dpsim_dp_f500_ph500_intp, 500)" + "ts_dpsim_dp_f500_ph500_intp_emt = ts.frequency_shift_list(\n", + " ts_dpsim_dp_f500_ph500_intp, 500\n", + ")" ] }, { @@ -505,22 +618,37 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_dpsim_emt_f500['v1'].time, ts_dpsim_emt_f500['v1'].values, color = '#939393ff')\n", - "plt.plot(ts_dpsim_emt_f500['v3'].time, ts_dpsim_emt_f500['v3'].values, color = '#939393ff')\n", - "plt.plot(ts_dpsim_dp_f500_ph500_intp_emt['v1_intpl_shift'].time, ts_dpsim_dp_f500_ph500_intp_emt['v1_intpl_shift'].values, linestyle='-.')\n", - "plt.plot(ts_dpsim_dp_f500_ph500_intp_emt['v3_intpl_shift'].time, ts_dpsim_dp_f500_ph500_intp_emt['v3_intpl_shift'].values, linestyle='-.')\n", - "plt.xlim([0,0.01])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (v)')\n", - "plt.title('DP 500Hz shift (10ms ts) vs EMT (10µs ts), 500Hz source')\n", + "plt.plot(\n", + " ts_dpsim_emt_f500[\"v1\"].time, ts_dpsim_emt_f500[\"v1\"].values, color=\"#939393ff\"\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_emt_f500[\"v3\"].time, ts_dpsim_emt_f500[\"v3\"].values, color=\"#939393ff\"\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f500_ph500_intp_emt[\"v1_intpl_shift\"].time,\n", + " ts_dpsim_dp_f500_ph500_intp_emt[\"v1_intpl_shift\"].values,\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_dp_f500_ph500_intp_emt[\"v3_intpl_shift\"].time,\n", + " ts_dpsim_dp_f500_ph500_intp_emt[\"v3_intpl_shift\"].values,\n", + " linestyle=\"-.\",\n", + ")\n", + "plt.xlim([0, 0.01])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (v)\")\n", + "plt.title(\"DP 500Hz shift (10ms ts) vs EMT (10µs ts), 500Hz source\")\n", "\n", "ts_dpsim_dp_f500_ph500_intp_phasors = ts.phasors(ts_dpsim_dp_f500_ph500_intp)\n", "plt.figure()\n", - "plt.plot(ts_dpsim_dp_f500_ph500_intp_phasors['v1_intpl']['phase'].time, ts_dpsim_dp_f500_ph500_intp_phasors['v1_intpl']['phase'].values)\n", - "plt.xlim([0,0.01])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.title('DP 500Hz shift (10ms ts), 500Hz source')" + "plt.plot(\n", + " ts_dpsim_dp_f500_ph500_intp_phasors[\"v1_intpl\"][\"phase\"].time,\n", + " ts_dpsim_dp_f500_ph500_intp_phasors[\"v1_intpl\"][\"phase\"].values,\n", + ")\n", + "plt.xlim([0, 0.01])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.title(\"DP 500Hz shift (10ms ts), 500Hz source\")" ] }, { @@ -556,10 +684,10 @@ "outputs": [], "source": [ "# read log file\n", - "work_dir = '../../../logs/DP_SynGenDq7odODE_ThreePhFault/'\n", - "log_name = 'DP_SynGenDq7odODE_ThreePhFault'\n", - "print(work_dir + log_name + '.csv')\n", - "ts_dpsim_ode_tpf = rt.read_timeseries_dpsim(work_dir + log_name + '.csv')\n", + "work_dir = \"../../../logs/DP_SynGenDq7odODE_ThreePhFault/\"\n", + "log_name = \"DP_SynGenDq7odODE_ThreePhFault\"\n", + "print(work_dir + log_name + \".csv\")\n", + "ts_dpsim_ode_tpf = rt.read_timeseries_dpsim(work_dir + log_name + \".csv\")\n", "ts_dpsim_ode_tpf_emt = ts.frequency_shift_list(ts_dpsim_ode_tpf, 60)\n", "ts_dpsim_ode_tpf_phasors = ts.phasors(ts_dpsim_ode_tpf)" ] @@ -574,12 +702,12 @@ "import os\n", "import urllib.request\n", "\n", - "if not os.path.exists('reference-results'):\n", - " os.mkdir('reference-results')\n", + "if not os.path.exists(\"reference-results\"):\n", + " os.mkdir(\"reference-results\")\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Simulink/SynchronousGenerator/SynGen_dq_7th_ThreePhFault/SL_SynGenDq7od_ThreePhFault_v_i.csv'\n", - "local_file = 'reference-results/SL_SynGenDq7od_ThreePhFault_v_i.csv'\n", - "urllib.request.urlretrieve(url, local_file) \n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Simulink/SynchronousGenerator/SynGen_dq_7th_ThreePhFault/SL_SynGenDq7od_ThreePhFault_v_i.csv\"\n", + "local_file = \"reference-results/SL_SynGenDq7od_ThreePhFault_v_i.csv\"\n", + "urllib.request.urlretrieve(url, local_file)\n", "\n", "ts_sl_tpf = rt.read_timeseries_simulink(local_file)" ] @@ -590,26 +718,41 @@ "metadata": {}, "outputs": [], "source": [ - "ts_sl_tpf_i1 = ts('i1', ts_sl_tpf['i1'].time, -ts_sl_tpf['i1'].values)\n", - "ts_sl_tpf_i2 = ts('i2', ts_sl_tpf['i2'].time, -ts_sl_tpf['i2'].values)\n", - "ts_sl_tpf_i3 = ts('i3', ts_sl_tpf['i3'].time, -ts_sl_tpf['i3'].values)\n", - "\n", - "ts_sl_tpf_i1.label = 'ia_sl'\n", - "ts_sl_tpf_i2.label = 'ib_sl'\n", - "ts_sl_tpf_i3.label = 'ic_sl'\n", - "ts_dpsim_ode_tpf_emt['i_gen_0_shift'].label = 'ia_dpsim'\n", - "ts_dpsim_ode_tpf_emt['i_gen_1_shift'].label = 'ib_dpsim'\n", - "ts_dpsim_ode_tpf_emt['i_gen_2_shift'].label = 'ic_dpsim'\n", - "plt.plot(ts_sl_tpf_i1.time, ts_sl_tpf_i1.values, color = '#939393ff')\n", - "plt.plot(ts_sl_tpf_i2.time, ts_sl_tpf_i2.values, color = '#939393ff')\n", - "plt.plot(ts_sl_tpf_i3.time, ts_sl_tpf_i3.values, color = '#939393ff')\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_0_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_0_shift'].values, linestyle='-.', color = '#d62728ff')\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_1_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_1_shift'].values, linestyle='-.', color = '#0055ffff')\n", - "plt.plot(ts_dpsim_ode_tpf_emt['i_gen_2_shift'].time, ts_dpsim_ode_tpf_emt['i_gen_2_shift'].values, linestyle='-.', color = '#00aa7fff')\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('voltage (V)')\n", - "plt.xlim(0.05,0.25)\n", - "plt.savefig('syngen_three_phase_fault.pdf')" + "ts_sl_tpf_i1 = ts(\"i1\", ts_sl_tpf[\"i1\"].time, -ts_sl_tpf[\"i1\"].values)\n", + "ts_sl_tpf_i2 = ts(\"i2\", ts_sl_tpf[\"i2\"].time, -ts_sl_tpf[\"i2\"].values)\n", + "ts_sl_tpf_i3 = ts(\"i3\", ts_sl_tpf[\"i3\"].time, -ts_sl_tpf[\"i3\"].values)\n", + "\n", + "ts_sl_tpf_i1.label = \"ia_sl\"\n", + "ts_sl_tpf_i2.label = \"ib_sl\"\n", + "ts_sl_tpf_i3.label = \"ic_sl\"\n", + "ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].label = \"ia_dpsim\"\n", + "ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].label = \"ib_dpsim\"\n", + "ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].label = \"ic_dpsim\"\n", + "plt.plot(ts_sl_tpf_i1.time, ts_sl_tpf_i1.values, color=\"#939393ff\")\n", + "plt.plot(ts_sl_tpf_i2.time, ts_sl_tpf_i2.values, color=\"#939393ff\")\n", + "plt.plot(ts_sl_tpf_i3.time, ts_sl_tpf_i3.values, color=\"#939393ff\")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_0_shift\"].values,\n", + " linestyle=\"-.\",\n", + " color=\"#d62728ff\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_1_shift\"].values,\n", + " linestyle=\"-.\",\n", + " color=\"#0055ffff\",\n", + ")\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].time,\n", + " ts_dpsim_ode_tpf_emt[\"i_gen_2_shift\"].values,\n", + " linestyle=\"-.\",\n", + " color=\"#00aa7fff\",\n", + ")\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"voltage (V)\")\n", + "plt.xlim(0.05, 0.25)\n", + "plt.savefig(\"syngen_three_phase_fault.pdf\")" ] }, { @@ -628,18 +771,21 @@ "outputs": [], "source": [ "plt.figure()\n", - "plt.plot(ts_dpsim_ode_tpf_phasors['i_gen_0']['phase'].time, ts_dpsim_ode_tpf_phasors['i_gen_0']['phase'].values)\n", - "plt.xlim([0.09,0.21])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('phase (deg)')\n", - "plt.savefig('syngen_three_phase_fault_phase.pdf')\n", + "plt.plot(\n", + " ts_dpsim_ode_tpf_phasors[\"i_gen_0\"][\"phase\"].time,\n", + " ts_dpsim_ode_tpf_phasors[\"i_gen_0\"][\"phase\"].values,\n", + ")\n", + "plt.xlim([0.09, 0.21])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"phase (deg)\")\n", + "plt.savefig(\"syngen_three_phase_fault_phase.pdf\")\n", "\n", "plt.figure()\n", - "plt.plot(ts_dpsim_ode_tpf['wr_gen'].time, ts_dpsim_ode_tpf['wr_gen'].values * 60)\n", - "plt.xlim([0.09,0.21])\n", - "plt.xlabel('time (s)')\n", - "plt.ylabel('rotor freq. (Hz)')\n", - "plt.savefig('syngen_three_phase_fault_wr.pdf')" + "plt.plot(ts_dpsim_ode_tpf[\"wr_gen\"].time, ts_dpsim_ode_tpf[\"wr_gen\"].values * 60)\n", + "plt.xlim([0.09, 0.21])\n", + "plt.xlabel(\"time (s)\")\n", + "plt.ylabel(\"rotor freq. (Hz)\")\n", + "plt.savefig(\"syngen_three_phase_fault_wr.pdf\")" ] }, { diff --git a/examples/Notebooks/matpower-case9.ipynb b/examples/Notebooks/matpower-case9.ipynb index c90df4fba9..392942c780 100644 --- a/examples/Notebooks/matpower-case9.ipynb +++ b/examples/Notebooks/matpower-case9.ipynb @@ -21,8 +21,9 @@ "outputs": [], "source": [ "import requests\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Matpower/case9results.mat'\n", - "with open('case9results.mat', 'wb') as out_file:\n", + "\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/reference-results/master/Matpower/case9results.mat\"\n", + "with open(\"case9results.mat\", \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)" ] @@ -34,7 +35,7 @@ "metadata": {}, "outputs": [], "source": [ - "mpc_reader = dpsim.matpower.Reader('case9results.mat', 'case9results')" + "mpc_reader = dpsim.matpower.Reader(\"case9results.mat\", \"case9results\")" ] }, { @@ -54,14 +55,14 @@ "metadata": {}, "outputs": [], "source": [ - "sim_name = 'case9'\n", - "dpsim.Logger.set_log_dir('logs/' + sim_name)\n", + "sim_name = \"case9\"\n", + "dpsim.Logger.set_log_dir(\"logs/\" + sim_name)\n", "logger = dpsim.Logger(sim_name)\n", "\n", "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node)\n", - " logger.log_attribute(node.name()+'.S', 's', node)\n", - " \n", + " logger.log_attribute(node.name() + \".V\", \"v\", node)\n", + " logger.log_attribute(node.name() + \".S\", \"s\", node)\n", + "\n", "# Parametrize and run simulation\n", "sim = dpsim.Simulation(sim_name, dpsim.LogLevel.info)\n", "sim.set_system(system)\n", @@ -84,7 +85,7 @@ "import villas.dataprocessing.readtools as rt\n", "from villas.dataprocessing.timeseries import TimeSeries as ts\n", "\n", - "log_file = 'logs/' + sim_name +'/' + sim_name + '.csv'\n", + "log_file = \"logs/\" + sim_name + \"/\" + sim_name + \".csv\"\n", "print(log_file)\n", "ts_dpsimpy = rt.read_timeseries_dpsim(log_file)" ] @@ -96,16 +97,26 @@ "metadata": {}, "outputs": [], "source": [ - "results = pd.DataFrame(columns=['Bus', 'V_mag(pu)', 'V_angle(deg)', 'P(MW)', 'Q (MVAr)'])\n", + "results = pd.DataFrame(\n", + " columns=[\"Bus\", \"V_mag(pu)\", \"V_angle(deg)\", \"P(MW)\", \"Q (MVAr)\"]\n", + ")\n", "\n", "for i in range(len(system.nodes)):\n", " node = system.nodes[i].name()\n", - " node_baseV = mpc_reader.mpc_bus_data.loc[mpc_reader.mpc_bus_data['bus_i'] == int(node), 'baseKV'].iloc[0] * 1e3\n", + " node_baseV = (\n", + " mpc_reader.mpc_bus_data.loc[\n", + " mpc_reader.mpc_bus_data[\"bus_i\"] == int(node), \"baseKV\"\n", + " ].iloc[0]\n", + " * 1e3\n", + " )\n", " w_mw = 1e-6\n", - " results.loc[i] = ([node] + [np.absolute(ts_dpsimpy[node + '.V'].values[-1]) / node_baseV]\n", - " + [np.degrees(np.angle(ts_dpsimpy[node + '.V'].values[-1]))] \n", - " + [w_mw * np.real(ts_dpsimpy[node + '.S'].values[-1])] \n", - " + [w_mw * np.imag(ts_dpsimpy[node + '.S'].values[-1])])" + " results.loc[i] = (\n", + " [node]\n", + " + [np.absolute(ts_dpsimpy[node + \".V\"].values[-1]) / node_baseV]\n", + " + [np.degrees(np.angle(ts_dpsimpy[node + \".V\"].values[-1]))]\n", + " + [w_mw * np.real(ts_dpsimpy[node + \".S\"].values[-1])]\n", + " + [w_mw * np.imag(ts_dpsimpy[node + \".S\"].values[-1])]\n", + " )" ] }, { @@ -126,11 +137,26 @@ "outputs": [], "source": [ "import scipy.io\n", - "input_mat = 'case9results.mat'\n", + "\n", + "input_mat = \"case9results.mat\"\n", "data = scipy.io.loadmat(input_mat)\n", - " \n", - "bus_data = pd.DataFrame(data['case9results'][0][0]['bus'])\n", - "bus_data.columns = [\"bus_i\", \"type\", \"Pd\", \"Qd\", \"Gs\", \"Bs\", \"area\", \"Vm\", \"Va\", \"baseKV\", \"zone\", \"Vmax\", \"Vmin\"]" + "\n", + "bus_data = pd.DataFrame(data[\"case9results\"][0][0][\"bus\"])\n", + "bus_data.columns = [\n", + " \"bus_i\",\n", + " \"type\",\n", + " \"Pd\",\n", + " \"Qd\",\n", + " \"Gs\",\n", + " \"Bs\",\n", + " \"area\",\n", + " \"Vm\",\n", + " \"Va\",\n", + " \"baseKV\",\n", + " \"zone\",\n", + " \"Vmax\",\n", + " \"Vmin\",\n", + "]" ] }, { @@ -150,7 +176,7 @@ "metadata": {}, "outputs": [], "source": [ - "assert all(bus_data['Vm'] - results['V_mag(pu)'] < 0.001)" + "assert all(bus_data[\"Vm\"] - results[\"V_mag(pu)\"] < 0.001)" ] }, { @@ -160,7 +186,7 @@ "metadata": {}, "outputs": [], "source": [ - "assert all(bus_data['Va'] - results['V_angle(deg)'] < 0.05)" + "assert all(bus_data[\"Va\"] - results[\"V_angle(deg)\"] < 0.05)" ] }, { diff --git a/examples/Python/Base/test_async.py b/examples/Python/Base/test_async.py index 5c96b22524..fb4e9b4154 100644 --- a/examples/Python/Base/test_async.py +++ b/examples/Python/Base/test_async.py @@ -6,31 +6,35 @@ from dpsim.Event import Event + def my_callback(event, sim, myvar): assert myvar == 1337 - print('Received Event: %s' % event) + print("Received Event: %s" % event) - if event in [ Event.done, Event.stopped, Event.stopped, Event.failed, Event.overrun ]: + if event in [Event.done, Event.stopped, Event.stopped, Event.failed, Event.overrun]: el = asyncio.get_event_loop() el.stop() + def test_async(): el = asyncio.get_event_loop() # Nodes gnd = dpsim.dp.Node.GND() - n1 = dpsim.dp.Node('n1') + n1 = dpsim.dp.Node("n1") # Components - v1 = dpsim.dp.ph1.VoltageSource('v_1', [gnd, n1], V_ref=complex(10,0)) - r1 = dpsim.dp.ph1.Resistor('r_1', [n1, gnd], R=1) + v1 = dpsim.dp.ph1.VoltageSource("v_1", [gnd, n1], V_ref=complex(10, 0)) + r1 = dpsim.dp.ph1.Resistor("r_1", [n1, gnd], R=1) system = dpsim.SystemTopology(50, [gnd, n1], [v1, r1]) start = dt.datetime.now() + dt.timedelta(seconds=4) - sim = dpsim.RealTimeSimulation(__name__, system, duration=10, timestep=0.0005)#, start_time=start) + sim = dpsim.RealTimeSimulation( + __name__, system, duration=10, timestep=0.0005 + ) # , start_time=start) # Start in two seconds! sim.start() @@ -46,5 +50,6 @@ def test_async(): el.run_forever() -if __name__ == '__main__': + +if __name__ == "__main__": test_async() diff --git a/examples/Python/Base/test_attribute.py b/examples/Python/Base/test_attribute.py index 845f9e9b03..d8dba4f1e6 100644 --- a/examples/Python/Base/test_attribute.py +++ b/examples/Python/Base/test_attribute.py @@ -1,43 +1,48 @@ import dpsim import pytest + def test_read(): gnd = dpsim.dp.Node.GND() - c = dpsim.dp.ph1.Capacitor('c1', [gnd, gnd], C=1.234); + c = dpsim.dp.ph1.Capacitor("c1", [gnd, gnd], C=1.234) assert c.C == 1.234 - assert c.name == 'c1' + assert c.name == "c1" + def test_write(): gnd = dpsim.dp.Node.GND() - c = dpsim.dp.ph1.Capacitor('c1', [gnd, gnd], C=1.234); + c = dpsim.dp.ph1.Capacitor("c1", [gnd, gnd], C=1.234) c.C = 5 assert c.C == 5 + def test_invalid(): with pytest.raises(AttributeError) as e_info: gnd = dpsim.dp.Node.GND() - c = dpsim.dp.ph1.Capacitor('c1', [gnd, gnd], C=1.234); + c = dpsim.dp.ph1.Capacitor("c1", [gnd, gnd], C=1.234) # dp.Capacitor does not have an attribute named 'doesnotexist' # Accessing it should throw a AttributeError exception! x = c.doesnotexist + def test_access(): with pytest.raises(AttributeError) as e_info: gnd = dpsim.dp.Node.GND() - c = dpsim.dp.ph1.Capacitor('c1', [gnd, gnd], C=1.234); + c = dpsim.dp.ph1.Capacitor("c1", [gnd, gnd], C=1.234) # Current is a read-only property. # This should throw a AttributeError exception! c.current = 5 + def test_type(): with pytest.raises(TypeError) as e_info: gnd = dpsim.dp.Node.GND() - c = dpsim.dp.ph1.Capacitor('c1', [gnd, gnd], C=1.234); + c = dpsim.dp.ph1.Capacitor("c1", [gnd, gnd], C=1.234) # Capacitance is a real valued property. # Assigning a complex number should throw a TypeError exception! diff --git a/examples/Python/Base/test_simulation.py b/examples/Python/Base/test_simulation.py index e4a5802167..f6444a0c5d 100644 --- a/examples/Python/Base/test_simulation.py +++ b/examples/Python/Base/test_simulation.py @@ -4,13 +4,14 @@ from dpsim.Event import Event + def test_simulation(): logging.getLogger().setLevel(logging.DEBUG) - logging.info('hello\n') + logging.info("hello\n") - n1 = dpsim.dp.Node('n1') + n1 = dpsim.dp.Node("n1") gnd = dpsim.dp.Node.GND() - r = dpsim.dp.ph1.Resistor('r1', [gnd, n1]) + r = dpsim.dp.ph1.Resistor("r1", [gnd, n1]) sys = dpsim.SystemTopology(50, [n1], [r]) @@ -48,5 +49,6 @@ def test_simulation(): assert sim.wait_until() == Event.stopping assert sim.wait_until() == Event.stopped -if __name__ == '__main__': + +if __name__ == "__main__": test_simulation() diff --git a/examples/Python/Base/test_singlestepping.py b/examples/Python/Base/test_singlestepping.py index 874ebe2593..06e24e1d0e 100644 --- a/examples/Python/Base/test_singlestepping.py +++ b/examples/Python/Base/test_singlestepping.py @@ -4,25 +4,28 @@ from dpsim.Event import Event + def test_simulation(): logging.getLogger().setLevel(logging.DEBUG) - logging.info('hello\n') + logging.info("hello\n") - n1 = dpsim.dp.Node('n1') + n1 = dpsim.dp.Node("n1") gnd = dpsim.dp.Node.GND() - r = dpsim.dp.ph1.Resistor('r1', [gnd, n1]) + r = dpsim.dp.ph1.Resistor("r1", [gnd, n1]) sys = dpsim.SystemTopology(50, [n1], [r]) - sim = dpsim.Simulation(__name__, sys, duration=10, rt=True, pbar=True, single_stepping=True) + sim = dpsim.Simulation( + __name__, sys, duration=10, rt=True, pbar=True, single_stepping=True + ) sim.step() assert sim.wait_until() == Event.starting assert sim.wait_until() == Event.running assert sim.wait_until() == Event.paused - for x in range(2,10): + for x in range(2, 10): sim.step() assert sim.wait_until() == Event.resuming assert sim.wait_until() == Event.running @@ -34,5 +37,5 @@ def test_simulation(): assert sim.wait_until() == Event.stopped -if __name__ == '__main__': +if __name__ == "__main__": test_simulation() diff --git a/examples/Python/CIM/dpsim-cim.py b/examples/Python/CIM/dpsim-cim.py index ce4c8d9a30..5b4eb5715a 100644 --- a/examples/Python/CIM/dpsim-cim.py +++ b/examples/Python/CIM/dpsim-cim.py @@ -1,6 +1,7 @@ import sys import dpsim + def run_cim(): if len(sys.argv) <= 1: print("usage: %s CIM_FILES" % sys.argv[0]) @@ -16,7 +17,7 @@ def run_cim(): sw.resistance_open = 1e9 sw.resistance_closed = 0.1 sw.closed = False - sw.connect([ dpsim.dp.Node.GND(), system.nodes["BUS9"] ]) + sw.connect([dpsim.dp.Node.GND(), system.nodes["BUS9"]]) system.add_component(sw) @@ -24,5 +25,6 @@ def run_cim(): sim.add_switch_event(sw, 0.05, True) sim.run() + if __name__ == "__main__": run_cim() diff --git a/examples/Python/Circuits/test_circuit.py b/examples/Python/Circuits/test_circuit.py index 0533d57db4..8df12bfdfb 100644 --- a/examples/Python/Circuits/test_circuit.py +++ b/examples/Python/Circuits/test_circuit.py @@ -3,22 +3,23 @@ PATH = os.path.dirname(__file__) + def test_circuit(): # Nodes gnd = dpsim.dp.Node.GND() - n1 = dpsim.dp.Node('n1') - n2 = dpsim.dp.Node('n2') - n3 = dpsim.dp.Node('n3') + n1 = dpsim.dp.Node("n1") + n2 = dpsim.dp.Node("n2") + n3 = dpsim.dp.Node("n3") # Components - v1 = dpsim.dp.ph1.VoltageSource('v_1') - v1.V_ref= complex(10, 0) - lL = dpsim.dp.ph1.Inductor('l_L') - lL.L= 0.001 - rL = dpsim.dp.ph1.Resistor('r_L') - rL.R= 0.1 - r1 = dpsim.dp.ph1.Resistor('r_1') - r1.R= 20 + v1 = dpsim.dp.ph1.VoltageSource("v_1") + v1.V_ref = complex(10, 0) + lL = dpsim.dp.ph1.Inductor("l_L") + lL.L = 0.001 + rL = dpsim.dp.ph1.Resistor("r_L") + rL.R = 0.1 + r1 = dpsim.dp.ph1.Resistor("r_1") + r1.R = 20 v1.connect([gnd, n1]) lL.connect([n2, n3]) @@ -30,16 +31,17 @@ def test_circuit(): sim = dpsim.Simulation(__name__, system, duration=0.2, timestep=0.0005) sim.run() - #results = rt.read_timeseries_dpsim_cmpl('Logs/' + sim.name + '_LeftVector.csv') - #expected = rt.read_timeseries_dpsim_real('examples/Results/Simulink/Circuits/SL_' + sim.name() + '.csv') + # results = rt.read_timeseries_dpsim_cmpl('Logs/' + sim.name + '_LeftVector.csv') + # expected = rt.read_timeseries_dpsim_real('examples/Results/Simulink/Circuits/SL_' + sim.name() + '.csv') err = 0 - #err += ts.TimeSeries.rmse(expected[0], results[0].dynphasor_shift_to_emt('n1_emt', 50)) - #err += ts.TimeSeries.rmse(expected[1], results[1].dynphasor_shift_to_emt('n2_emt', 50)) + # err += ts.TimeSeries.rmse(expected[0], results[0].dynphasor_shift_to_emt('n1_emt', 50)) + # err += ts.TimeSeries.rmse(expected[1], results[1].dynphasor_shift_to_emt('n2_emt', 50)) - print('Total RMSE: %g' % (err)) + print("Total RMSE: %g" % (err)) assert err < 1e-4 -if __name__ == '__main__': + +if __name__ == "__main__": test_circuit() diff --git a/examples/Python/RealTime/test_realtime.py b/examples/Python/RealTime/test_realtime.py index 560030cfff..15e2d2f0bc 100644 --- a/examples/Python/RealTime/test_realtime.py +++ b/examples/Python/RealTime/test_realtime.py @@ -3,15 +3,16 @@ from dpsim.Event import Event + def test_realtime(): # Nodes gnd = dpsim.dp.Node.GND() - n1 = dpsim.dp.Node('n1') + n1 = dpsim.dp.Node("n1") # Components - v1 = dpsim.dp.ph1.VoltageSource('v_1') + v1 = dpsim.dp.ph1.VoltageSource("v_1") v1.V_ref = complex(10, 0) - r1 = dpsim.dp.ph1.Resistor('r_1') + r1 = dpsim.dp.ph1.Resistor("r_1") r1.R = 1 v1.connect([gnd, n1]) @@ -23,10 +24,13 @@ def test_realtime(): print(repr(start)) - sim = dpsim.RealTimeSimulation(__name__, system, duration=10, timestep=0.001, start_time=start) + sim = dpsim.RealTimeSimulation( + __name__, system, duration=10, timestep=0.001, start_time=start + ) sim.show_progressbar() sim.run(pbar=True) -if __name__ == '__main__': + +if __name__ == "__main__": test_realtime() diff --git a/examples/Python/RuntimeMeas/decoupling_9bus_comp.py b/examples/Python/RuntimeMeas/decoupling_9bus_comp.py index 12865cecd8..73cd8346c4 100644 --- a/examples/Python/RuntimeMeas/decoupling_9bus_comp.py +++ b/examples/Python/RuntimeMeas/decoupling_9bus_comp.py @@ -12,42 +12,51 @@ from villas.dataprocessing.timeseries import TimeSeries as ts import matplotlib.pyplot as plt + def multiply_decoupled(sys, num_copies, nodes, resistance, inductance, capacitance): sys.multiply(num_copies) counter = 0 for orig_node in nodes: node_names = [orig_node] - node_names += [orig_node + '_' + str(i) for i in range(2, num_copies+2)] + node_names += [orig_node + "_" + str(i) for i in range(2, num_copies + 2)] node_names.append(orig_node) - for i in range(0, num_copies+1): - sys.add_decoupling_line('dline' + str(counter), sys.nodes[node_names[i]], sys.nodes[node_names[i+1]], resistance, inductance, capacitance) + for i in range(0, num_copies + 1): + sys.add_decoupling_line( + "dline" + str(counter), + sys.nodes[node_names[i]], + sys.nodes[node_names[i + 1]], + resistance, + inductance, + capacitance, + ) counter += 1 + def multiply_coupled(sys, num_copies, nodes, resistance, inductance, capacitance): gnd = dpsim.dp.Node.GND() sys.multiply(num_copies) counter = 0 for orig_node in nodes: node_names = [orig_node] - node_names += [orig_node + '_' + str(i) for i in range(2, num_copies+2)] + node_names += [orig_node + "_" + str(i) for i in range(2, num_copies + 2)] node_names.append(orig_node) - for i in range(0, num_copies+1): + for i in range(0, num_copies + 1): # TODO lumped resistance? - rl_node = dpsim.dp.Node('N_add_' + str(counter)) - res = dpsim.dp.ph1.Resistor('R_' + str(counter)) + rl_node = dpsim.dp.Node("N_add_" + str(counter)) + res = dpsim.dp.ph1.Resistor("R_" + str(counter)) res.R = resistance - ind = dpsim.dp.ph1.Inductor('L_' + str(counter)) + ind = dpsim.dp.ph1.Inductor("L_" + str(counter)) ind.L = inductance - cap1 = dpsim.dp.ph1.Capacitor('C1_' + str(counter)) + cap1 = dpsim.dp.ph1.Capacitor("C1_" + str(counter)) cap1.C = capacitance / 2 - cap2 = dpsim.dp.ph1.Capacitor('C2_' + str(counter)) + cap2 = dpsim.dp.ph1.Capacitor("C2_" + str(counter)) cap2.C = capacitance / 2 sys.add_node(rl_node) res.connect([sys.nodes[node_names[i]], rl_node]) - ind.connect([rl_node, sys.nodes[node_names[i+1]]]) + ind.connect([rl_node, sys.nodes[node_names[i + 1]]]) cap1.connect([sys.nodes[node_names[i]], gnd]) - cap2.connect([sys.nodes[node_names[i+1]], gnd]) + cap2.connect([sys.nodes[node_names[i + 1]], gnd]) counter += 1 sys.add_component(res) @@ -55,29 +64,39 @@ def multiply_coupled(sys, num_copies, nodes, resistance, inductance, capacitance sys.add_component(cap1) sys.add_component(cap2) + def do_sim(name, system): logger = dpsim.Logger(name) for i in range(0, 6): - logger.log_attribute(system.nodes['BUS' + str(i+4)], 'v') - - sim = dpsim.Simulation(name, system, timestep=0.0001, duration=0.1, init_steady_state=False, pbar=False, split_subnets=True) - sim.set_scheduler('thread_level', threads=4) + logger.log_attribute(system.nodes["BUS" + str(i + 4)], "v") + + sim = dpsim.Simulation( + name, + system, + timestep=0.0001, + duration=0.1, + init_steady_state=False, + pbar=False, + split_subnets=True, + ) + sim.set_scheduler("thread_level", threads=4) sim.add_logger(logger) sim.run() -name = 'WSCC-9bus' -files = glob.glob('../dpsim/examples/CIM/WSCC-09_RX/*.xml') + +name = "WSCC-9bus" +files = glob.glob("../dpsim/examples/CIM/WSCC-09_RX/*.xml") system = dpsim.load_cim(name, files, frequency=60) -do_sim('normal', system) +do_sim("normal", system) system = dpsim.load_cim(name, files, frequency=60) -multiply_coupled(system, 1, ['BUS5', 'BUS6', 'BUS8'], 100, 0.16, 1e-6) -do_sim('coupled', system) +multiply_coupled(system, 1, ["BUS5", "BUS6", "BUS8"], 100, 0.16, 1e-6) +do_sim("coupled", system) system = dpsim.load_cim(name, files, frequency=60) -multiply_decoupled(system, 1, ['BUS5', 'BUS6', 'BUS8'], 100, 0.16, 1e-6) -do_sim('decoupled', system) +multiply_decoupled(system, 1, ["BUS5", "BUS6", "BUS8"], 100, 0.16, 1e-6) +do_sim("decoupled", system) normal_dp = rt.read_timeseries_dpsim("Logs/normal.csv") normal_emt = ts.frequency_shift_list(normal_dp, 60) @@ -89,17 +108,16 @@ def do_sim(name, system): decoupled_emt = ts.frequency_shift_list(decoupled_dp, 60) for i in range(0, 6): - varname = 'BUS' + str(i+4) + '.v' -#varname = 'BUS4.v' -#i = 0 - pt.set_timeseries_labels(normal_emt[varname], varname + ' normal') - pt.set_timeseries_labels(coupled_emt[varname], varname + ' coupled') - pt.set_timeseries_labels(decoupled_emt[varname], varname + ' decoupled') - pt.plot_timeseries(i+1, normal_emt[varname]) - pt.plot_timeseries(i+1, coupled_emt[varname]) - pt.plot_timeseries(i+1, decoupled_emt[varname]) - plt.title('WSCC-09_RX with copy connected by lines (100 Ohm, 0.16 H, 1e-6 F)') - plt.xlabel('Time [s]') - plt.ylabel('Voltage [V]') + varname = "BUS" + str(i + 4) + ".v" + + pt.set_timeseries_labels(normal_emt[varname], varname + " normal") + pt.set_timeseries_labels(coupled_emt[varname], varname + " coupled") + pt.set_timeseries_labels(decoupled_emt[varname], varname + " decoupled") + pt.plot_timeseries(i + 1, normal_emt[varname]) + pt.plot_timeseries(i + 1, coupled_emt[varname]) + pt.plot_timeseries(i + 1, decoupled_emt[varname]) + plt.title("WSCC-09_RX with copy connected by lines (100 Ohm, 0.16 H, 1e-6 F)") + plt.xlabel("Time [s]") + plt.ylabel("Voltage [V]") plt.show() diff --git a/examples/Python/RuntimeMeas/decoupling_9bus_existing.py b/examples/Python/RuntimeMeas/decoupling_9bus_existing.py index fa7b6636a7..138e232c45 100644 --- a/examples/Python/RuntimeMeas/decoupling_9bus_existing.py +++ b/examples/Python/RuntimeMeas/decoupling_9bus_existing.py @@ -12,15 +12,17 @@ from villas.dataprocessing.timeseries import TimeSeries as ts import matplotlib.pyplot as plt + def decouple_line(sys, line, node1, node2): orig_line = system.component(line) sys.remove_component(line) - R_line = orig_line.attr('R_series').get() - L_line = orig_line.attr('L_series').get() - C_line = orig_line.attr('C_parallel').get() + R_line = orig_line.attr("R_series").get() + L_line = orig_line.attr("L_series").get() + C_line = orig_line.attr("C_parallel").get() - line = dpsimpy.signal.DecouplingLine('dline_' + node1 + '_' + node2, - dpsimpy.LogLevel.info) + line = dpsimpy.signal.DecouplingLine( + "dline_" + node1 + "_" + node2, dpsimpy.LogLevel.info + ) line.set_parameters(sys.node(node1), sys.node(node2), R_line, L_line, C_line) # TODO: Probably interestingn to add the line this way @@ -29,12 +31,13 @@ def decouple_line(sys, line, node1, node2): sys.add_component(line) sys.add_components(line.get_line_components()) + def do_sim(name, system): logger = dpsimpy.Logger(name) - logger.log_attribute('BUS5.V', 'v', system.node('BUS5')) - logger.log_attribute('BUS6.V', 'v', system.node('BUS6')) - logger.log_attribute('BUS8.V', 'v', system.node('BUS8')) + logger.log_attribute("BUS5.V", "v", system.node("BUS5")) + logger.log_attribute("BUS6.V", "v", system.node("BUS6")) + logger.log_attribute("BUS8.V", "v", system.node("BUS8")) sim = dpsimpy.Simulation(name, dpsimpy.LogLevel.debug) sim.set_system(system) @@ -46,22 +49,40 @@ def do_sim(name, system): sim.add_logger(logger) sim.run() -name = 'WSCC-9bus' -dpsim_root_dir = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8') +name = "WSCC-9bus" + +dpsim_root_dir = ( + subprocess.Popen(["git", "rev-parse", "--show-toplevel"], stdout=subprocess.PIPE) + .communicate()[0] + .rstrip() + .decode("utf-8") +) -files = glob.glob(dpsim_root_dir + '/build/_deps/cim-data-src/WSCC-09/WSCC-09/*.xml') +files = glob.glob(dpsim_root_dir + "/build/_deps/cim-data-src/WSCC-09/WSCC-09/*.xml") reader_normal = dpsimpy.CIMReader(name) -system = reader_normal.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.IdealVoltageSource) -do_sim('normal', system) +system = reader_normal.loadCIM( + 60, + files, + dpsimpy.Domain.DP, + dpsimpy.PhaseType.Single, + dpsimpy.GeneratorType.IdealVoltageSource, +) +do_sim("normal", system) reader_decoupled = dpsimpy.CIMReader(name) -system = reader_decoupled.loadCIM(60, files, dpsimpy.Domain.DP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.IdealVoltageSource) -decouple_line(system, 'LINE75', 'BUS5', 'BUS7') -#decouple_line(system, 'LINE78', 'BUS7', 'BUS8') -decouple_line(system, 'LINE64', 'BUS6', 'BUS4') -decouple_line(system, 'LINE89', 'BUS8', 'BUS9') -do_sim('decoupled', system) +system = reader_decoupled.loadCIM( + 60, + files, + dpsimpy.Domain.DP, + dpsimpy.PhaseType.Single, + dpsimpy.GeneratorType.IdealVoltageSource, +) +decouple_line(system, "LINE75", "BUS5", "BUS7") +# decouple_line(system, 'LINE78', 'BUS7', 'BUS8') +decouple_line(system, "LINE64", "BUS6", "BUS4") +decouple_line(system, "LINE89", "BUS8", "BUS9") +do_sim("decoupled", system) normal_dp = rt.read_timeseries_dpsim("logs/normal.csv") normal_emt = ts.frequency_shift_list(normal_dp, 60) @@ -70,13 +91,13 @@ def do_sim(name, system): decoupled_emt = ts.frequency_shift_list(decoupled_dp, 60) for i, v in enumerate([5, 6, 8]): - varname = 'BUS' + str(v) + '.V_shift' - pt.set_timeseries_labels(normal_emt[varname], varname + ' normal') - pt.set_timeseries_labels(decoupled_emt[varname], varname + ' decoupled') - pt.plot_timeseries(i+1, normal_emt[varname]) - pt.plot_timeseries(i+1, decoupled_emt[varname]) - plt.title('WSCC-09 with 3 lines replaced by decoupling equivalents') - plt.xlabel('Time [s]') - plt.ylabel('Voltage [V]') + varname = "BUS" + str(v) + ".V_shift" + pt.set_timeseries_labels(normal_emt[varname], varname + " normal") + pt.set_timeseries_labels(decoupled_emt[varname], varname + " decoupled") + pt.plot_timeseries(i + 1, normal_emt[varname]) + pt.plot_timeseries(i + 1, decoupled_emt[varname]) + plt.title("WSCC-09 with 3 lines replaced by decoupling equivalents") + plt.xlabel("Time [s]") + plt.ylabel("Voltage [V]") plt.show() diff --git a/examples/Python/RuntimeMeas/decoupling_sched.py b/examples/Python/RuntimeMeas/decoupling_sched.py index 89a3d5fcbf..fa2f3d784f 100644 --- a/examples/Python/RuntimeMeas/decoupling_sched.py +++ b/examples/Python/RuntimeMeas/decoupling_sched.py @@ -5,6 +5,7 @@ from meas_utils import * + def decoupling_sched(instance, sizes, schedulers): times = {} sigmas = {} @@ -13,42 +14,47 @@ def decoupling_sched(instance, sizes, schedulers): sigmas[scheduler] = [] for size in sizes: sched_name, args = map_scheduler(scheduler, size) - if 'in_measurement_file' in list(args.keys()): + if "in_measurement_file" in list(args.keys()): do_meas(instance, size) - time, sigma = instance.do_sim(scheduler=sched_name, scheduler_args=args, size=size) + time, sigma = instance.do_sim( + scheduler=sched_name, scheduler_args=args, size=size + ) times[scheduler].append(time) sigmas[scheduler].append(sigma) - return Measurement(instance, sizes, 'size', times, sigma=sigmas) + return Measurement(instance, sizes, "size", times, sigma=sigmas) + -if __name__ == '__main__': - name = 'decoupling_sched' +if __name__ == "__main__": + name = "decoupling_sched" if len(sys.argv) > 1: name = sys.argv[1] - instance = SimInstance(name, glob.glob('../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml'), 60.0, 10) + instance = SimInstance( + name, glob.glob("../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml"), 60.0, 10 + ) instance.sim_args = { - 'timestep': 0.0001, - 'duration': 0.1, - 'init_steady_state': False, - 'pbar': False, - 'split_subnets': True, - 'log_level': 0, + "timestep": 0.0001, + "duration": 0.1, + "init_steady_state": False, + "pbar": False, + "split_subnets": True, + "log_level": 0, } instance.copy_settings = { - 'decouple': True, - #'decouple': 'diakoptics', - 'nodes': ['BUS5', 'BUS6', 'BUS8'], - 'resistance': 100, - 'inductance': 0.16, - 'capacitance': 1e-6, + "decouple": True, + # 'decouple': 'diakoptics', + "nodes": ["BUS5", "BUS6", "BUS8"], + "resistance": 100, + "inductance": 0.16, + "capacitance": 1e-6, } schedulers = { - 'omp_level 8', - 'thread_level 8', - 'thread_level meas 8', - 'thread_list 8', - 'thread_list meas 8', + "omp_level 8", + "thread_level 8", + "thread_level meas 8", + "thread_list 8", + "thread_list meas 8", } sizes = range(1, 41) diff --git a/examples/Python/RuntimeMeas/diakoptics_splitsize.py b/examples/Python/RuntimeMeas/diakoptics_splitsize.py index 0e61bb39ac..1cb2f1182b 100644 --- a/examples/Python/RuntimeMeas/diakoptics_splitsize.py +++ b/examples/Python/RuntimeMeas/diakoptics_splitsize.py @@ -5,6 +5,7 @@ from meas_utils import * + def diakoptics_splitsize(instance, size, splits, scheduler): times = {} sigmas = {} @@ -13,40 +14,45 @@ def diakoptics_splitsize(instance, size, splits, scheduler): sigmas[scheduler] = [] for split in splits: sched_name, args = map_scheduler(scheduler, size) - if 'in_measurement_file' in list(args.keys()): + if "in_measurement_file" in list(args.keys()): do_meas(instance, size) - instance.copy_settings['splits'] = split - time, sigma = instance.do_sim(scheduler=sched_name, scheduler_args=args, size=size) + instance.copy_settings["splits"] = split + time, sigma = instance.do_sim( + scheduler=sched_name, scheduler_args=args, size=size + ) times[scheduler].append(time) sigmas[scheduler].append(sigma) - return Measurement(instance, splits, 'splits', times, sigma=sigmas) + return Measurement(instance, splits, "splits", times, sigma=sigmas) + -if __name__ == '__main__': - name = 'diakoptics_splitsize' +if __name__ == "__main__": + name = "diakoptics_splitsize" if len(sys.argv) > 1: name = sys.argv[1] - instance = SimInstance(name, glob.glob('../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml'), 60.0, 10) + instance = SimInstance( + name, glob.glob("../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml"), 60.0, 10 + ) instance.sim_args = { - 'timestep': 0.0001, - 'duration': 0.1, - 'init_steady_state': False, - 'pbar': False, - 'split_subnets': True, - 'log_level': 0, + "timestep": 0.0001, + "duration": 0.1, + "init_steady_state": False, + "pbar": False, + "split_subnets": True, + "log_level": 0, } instance.copy_settings = { - #'decouple': True, - 'decouple': 'diakoptics', - 'nodes': ['BUS5', 'BUS6', 'BUS8'], - 'resistance': 100, - 'inductance': 0.16, - 'capacitance': 1e-6, + # 'decouple': True, + "decouple": "diakoptics", + "nodes": ["BUS5", "BUS6", "BUS8"], + "resistance": 100, + "inductance": 0.16, + "capacitance": 1e-6, } schedulers = { - 'sequential', - 'omp_level 8', + "sequential", + "omp_level 8", } size = 60 diff --git a/examples/Python/RuntimeMeas/fix_powertransformers.py b/examples/Python/RuntimeMeas/fix_powertransformers.py index cebb6727af..ea54180b5b 100644 --- a/examples/Python/RuntimeMeas/fix_powertransformers.py +++ b/examples/Python/RuntimeMeas/fix_powertransformers.py @@ -4,26 +4,32 @@ import xml.etree.ElementTree if len(sys.argv) != 3: - sys.exit('usage: fix_powertransformers.py ') + sys.exit("usage: fix_powertransformers.py ") tree = xml.etree.ElementTree.parse(sys.argv[1]) -ns = {'cim': 'http://iec.ch/TC57/2009/CIM-schema-cim14#', - 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'} +ns = { + "cim": "http://iec.ch/TC57/2009/CIM-schema-cim14#", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", +} pt_ends = dict() -for pt_end in tree.iterfind('cim:PowerTransformerEnd', namespaces=ns): - pt_ends[pt_end.get('{'+ns['rdf']+'}ID')] = pt_end +for pt_end in tree.iterfind("cim:PowerTransformerEnd", namespaces=ns): + pt_ends[pt_end.get("{" + ns["rdf"] + "}ID")] = pt_end -for terminal in tree.iterfind('cim:Terminal', ns): - condeq = terminal.find('cim:Terminal.ConductingEquipment', ns) - condeq_id = condeq.get('{'+ns['rdf']+'}resource')[1:] +for terminal in tree.iterfind("cim:Terminal", ns): + condeq = terminal.find("cim:Terminal.ConductingEquipment", ns) + condeq_id = condeq.get("{" + ns["rdf"] + "}resource")[1:] if condeq_id in pt_ends: pt_end = pt_ends[condeq_id] - pt_id = pt_end.find('cim:PowerTransformerEnd.MemberOf_PowerTransformer', ns).get('{'+ns['rdf']+'}resource')[1:] - terminal_id = terminal.get('{'+ns['rdf']+'}ID') - end_term = xml.etree.ElementTree.Element('cim:TransformerEnd.Terminal', {'rdf:resource': '#' + terminal_id}) + pt_id = pt_end.find( + "cim:PowerTransformerEnd.MemberOf_PowerTransformer", ns + ).get("{" + ns["rdf"] + "}resource")[1:] + terminal_id = terminal.get("{" + ns["rdf"] + "}ID") + end_term = xml.etree.ElementTree.Element( + "cim:TransformerEnd.Terminal", {"rdf:resource": "#" + terminal_id} + ) pt_end.append(end_term) - condeq.set('{'+ns['rdf']+'}resource', '#'+pt_id) + condeq.set("{" + ns["rdf"] + "}resource", "#" + pt_id) tree.write(sys.argv[2]) diff --git a/examples/Python/RuntimeMeas/meas_utils.py b/examples/Python/RuntimeMeas/meas_utils.py index 9bf58f6ec9..35cc8c9619 100644 --- a/examples/Python/RuntimeMeas/meas_utils.py +++ b/examples/Python/RuntimeMeas/meas_utils.py @@ -11,42 +11,51 @@ import _dpsim import matplotlib.pyplot as plt + def multiply_decoupled(sys, num_copies, nodes, resistance, inductance, capacitance): sys.multiply(num_copies) counter = 0 for orig_node in nodes: node_names = [orig_node] - node_names += [orig_node + '_' + str(i) for i in range(2, num_copies+2)] + node_names += [orig_node + "_" + str(i) for i in range(2, num_copies + 2)] node_names.append(orig_node) - for i in range(0, num_copies+1): - sys.add_decoupling_line('dline' + str(counter), sys.nodes[node_names[i]], sys.nodes[node_names[i+1]], resistance, inductance, capacitance) + for i in range(0, num_copies + 1): + sys.add_decoupling_line( + "dline" + str(counter), + sys.nodes[node_names[i]], + sys.nodes[node_names[i + 1]], + resistance, + inductance, + capacitance, + ) counter += 1 + def multiply_coupled(sys, num_copies, nodes, resistance, inductance, capacitance): gnd = dpsim.dp.Node.GND() sys.multiply(num_copies) counter = 0 for orig_node in nodes: node_names = [orig_node] - node_names += [orig_node + '_' + str(i) for i in range(2, num_copies+2)] + node_names += [orig_node + "_" + str(i) for i in range(2, num_copies + 2)] node_names.append(orig_node) - for i in range(0, num_copies+1): + for i in range(0, num_copies + 1): # TODO lumped resistance? - rl_node = dpsim.dp.Node('N_add_' + str(counter)) - res = dpsim.dp.ph1.Resistor('R_' + str(counter)) + rl_node = dpsim.dp.Node("N_add_" + str(counter)) + res = dpsim.dp.ph1.Resistor("R_" + str(counter)) res.R = resistance - ind = dpsim.dp.ph1.Inductor('L_' + str(counter)) + ind = dpsim.dp.ph1.Inductor("L_" + str(counter)) ind.L = inductance - cap1 = dpsim.dp.ph1.Capacitor('C1_' + str(counter)) + cap1 = dpsim.dp.ph1.Capacitor("C1_" + str(counter)) cap1.C = capacitance / 2 - cap2 = dpsim.dp.ph1.Capacitor('C2_' + str(counter)) + cap2 = dpsim.dp.ph1.Capacitor("C2_" + str(counter)) cap2.C = capacitance / 2 sys.add_node(rl_node) res.connect([sys.nodes[node_names[i]], rl_node]) - ind.connect([rl_node, sys.nodes[node_names[i+1]]]) + ind.connect([rl_node, sys.nodes[node_names[i + 1]]]) cap1.connect([sys.nodes[node_names[i]], gnd]) - cap2.connect([sys.nodes[node_names[i+1]], gnd]) + cap2.connect([sys.nodes[node_names[i + 1]], gnd]) counter += 1 sys.add_component(res) @@ -54,25 +63,28 @@ def multiply_coupled(sys, num_copies, nodes, resistance, inductance, capacitance sys.add_component(cap1) sys.add_component(cap2) -def multiply_diakoptics(sys, num_copies, nodes, resistance, inductance, capacitance, splits=0): + +def multiply_diakoptics( + sys, num_copies, nodes, resistance, inductance, capacitance, splits=0 +): gnd = dpsim.dp.Node.GND() sys.multiply(num_copies) counter = 0 tear_components = [] if splits > 0: - split_every = int(num_copies+1) / splits + split_every = int(num_copies + 1) / splits else: split_every = 1 for orig_node in nodes: node_names = [orig_node] - node_names += [orig_node + '_' + str(i) for i in range(2, num_copies+2)] + node_names += [orig_node + "_" + str(i) for i in range(2, num_copies + 2)] node_names.append(orig_node) - for i in range(0, num_copies+1): - line = dpsim.dp.ph1.PiLine('line' + str(counter)) + for i in range(0, num_copies + 1): + line = dpsim.dp.ph1.PiLine("line" + str(counter)) line.R_series = resistance line.L_series = inductance line.C_parallel = capacitance - line.connect([sys.nodes[node_names[i]], sys.nodes[node_names[i+1]]]) + line.connect([sys.nodes[node_names[i]], sys.nodes[node_names[i + 1]]]) if i % split_every == 0: tear_components.append(line) else: @@ -80,32 +92,39 @@ def multiply_diakoptics(sys, num_copies, nodes, resistance, inductance, capacita counter += 1 return tear_components + def map_scheduler(sched_string, size=0): - parts = sched_string.split(' ') + parts = sched_string.split(" ") scheduler = parts[0] sched_args = {} for s in parts: if s.isdigit(): - sched_args['threads'] = int(s) - elif s == 'meas': + sched_args["threads"] = int(s) + elif s == "meas": if size: - sched_args['in_measurement_file'] = 'measurements_'+str(size)+'.txt' + sched_args["in_measurement_file"] = "measurements_" + str(size) + ".txt" else: - sched_args['in_measurement_file'] = 'measurements.txt' - elif s == 'cv': - sched_args['use_condition_variable'] = True - elif s == 'tasktype': - sched_args['sort_task_types'] = True + sched_args["in_measurement_file"] = "measurements.txt" + elif s == "cv": + sched_args["use_condition_variable"] = True + elif s == "tasktype": + sched_args["sort_task_types"] = True return (scheduler, sched_args) + def do_meas(instance, size=0): instance = copy.copy(instance) instance.repetitions = 1 if size: - filename = 'measurements_'+str(size)+'.txt' + filename = "measurements_" + str(size) + ".txt" else: - filename = 'measurements.txt' - instance.do_sim(scheduler='sequential', scheduler_args={'out_measurement_file': filename}, size=size) + filename = "measurements.txt" + instance.do_sim( + scheduler="sequential", + scheduler_args={"out_measurement_file": filename}, + size=size, + ) + def check_numa(): try: @@ -117,9 +136,10 @@ def check_numa(): if numa.get_max_node() > 0 and len(numa.get_run_on_node_mask()) > 1: print("Warning: NUMA settings may be suboptimal!", file=sys.stderr) + class SimInstance: - """ Helper class that embeds all parameters that stay constant for multiple - runs of a simulation, e.g. for a performance plot. + """Helper class that embeds all parameters that stay constant for multiple + runs of a simulation, e.g. for a performance plot. """ def __init__(self, name, files, frequency, repetitions=1): @@ -130,7 +150,7 @@ def __init__(self, name, files, frequency, repetitions=1): try: self.version = _dpsim.__version__ except: - self.version = 'unknown' + self.version = "unknown" self.hostname = socket.gethostname() self.sim_args = {} self.copy_settings = None @@ -140,31 +160,34 @@ def do_sim(self, scheduler=None, scheduler_args={}, size=1): if size > 1: # TODO a bit ugly copy_args = self.copy_settings.copy() - decouple = copy_args['decouple'] - del(copy_args['decouple']) + decouple = copy_args["decouple"] + del copy_args["decouple"] for i in range(0, self.repetitions): sys = dpsim.load_cim(self.name, self.files, self.frequency, log_level=0) if size > 1: - if decouple == 'diakoptics': - self.sim_args['tear_components'] = multiply_diakoptics(sys, size-1, **copy_args) + if decouple == "diakoptics": + self.sim_args["tear_components"] = multiply_diakoptics( + sys, size - 1, **copy_args + ) elif decouple: - multiply_decoupled(sys, size-1, **copy_args) + multiply_decoupled(sys, size - 1, **copy_args) else: - multiply_coupled(sys, size-1, **copy_args) + multiply_coupled(sys, size - 1, **copy_args) sim = dpsim.Simulation(self.name, sys, **self.sim_args) if scheduler: sim.set_scheduler(scheduler, **scheduler_args) sim.run() times.append(sim.avg_step_time) - if 'tear_components' in self.sim_args: - del(self.sim_args['tear_components']) - avg = sum(times)/len(times) - sigma = math.sqrt(sum([(x - avg)**2 for x in times]) / len(times)) + if "tear_components" in self.sim_args: + del self.sim_args["tear_components"] + avg = sum(times) / len(times) + sigma = math.sqrt(sum([(x - avg) ** 2 for x in times]) / len(times)) return (avg, sigma) + class Measurement: - """ Generalized set of measurements (usually wall clock times per timestep) - generated with the same, otherwise fixed settings. + """Generalized set of measurements (usually wall clock times per timestep) + generated with the same, otherwise fixed settings. """ def __init__(self, instance, xaxis, xlabel, data, name=None, sigma=None): @@ -183,26 +206,28 @@ def __init__(self, instance, xaxis, xlabel, data, name=None, sigma=None): @staticmethod def read_csv(filename): - with open(filename, 'r') as csvfile: + with open(filename, "r") as csvfile: reader = csv.DictReader(csvfile) xlabel = reader.fieldnames[0] data = {} sigma = {} xaxis = [] for name in reader.fieldnames[1:]: - if not name.startswith('sigma '): + if not name.startswith("sigma "): data[name] = [] sigma[name] = [] for row in reader: for k, v in row.items(): if k == xlabel: xaxis.append(int(v)) - elif k.startswith('sigma '): + elif k.startswith("sigma "): sigma[k[6:]].append(float(v)) else: data[k].append(float(v)) - return Measurement(None, xaxis, xlabel, data, filename.rstrip('.csv'), sigma) - + return Measurement( + None, xaxis, xlabel, data, filename.rstrip(".csv"), sigma + ) + def speedup(self, old, name): if self.xaxis != old.xaxis: raise ValueError("x axis mismatch") @@ -214,10 +239,10 @@ def speedup(self, old, name): return Measurement(None, self.xaxis, self.xlabel, data, name=name) def write_csv(self, filename): - with open(filename, 'w') as csvfile: + with open(filename, "w") as csvfile: fieldnames = [self.xlabel] + list(self.data.keys()) if self.sigma: - fieldnames += ['sigma ' + k for k in self.data.keys()] + fieldnames += ["sigma " + k for k in self.data.keys()] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() @@ -227,17 +252,19 @@ def write_csv(self, filename): row[k] = self.data[k][i] if self.sigma: for k in self.sigma.keys(): - row['sigma ' + k] = self.sigma[k][i] + row["sigma " + k] = self.sigma[k][i] writer.writerow(row) - + def write_settings(self, filename): - with open(filename, 'w') as f: + with open(filename, "w") as f: json.dump(self.instance.__dict__, f, indent=4) def plot(self, filename=None, **plot_args): for key, series in self.data.items(): if self.sigma and self.sigma[key]: - plt.errorbar(self.xaxis, series, self.sigma[key], label=key, **plot_args) + plt.errorbar( + self.xaxis, series, self.sigma[key], label=key, **plot_args + ) else: plt.plot(self.xaxis, series, label=key, **plot_args) plt.xlabel(self.xlabel) @@ -247,6 +274,6 @@ def plot(self, filename=None, **plot_args): def save(self): if self.instance: - self.write_settings(self.name + '.json') - self.write_csv(self.name + '.csv') - self.plot(self.name + '.svg') + self.write_settings(self.name + ".json") + self.write_csv(self.name + ".csv") + self.plot(self.name + ".svg") diff --git a/examples/Python/RuntimeMeas/mult_split.py b/examples/Python/RuntimeMeas/mult_split.py index d28def0bb8..23d052ac68 100644 --- a/examples/Python/RuntimeMeas/mult_split.py +++ b/examples/Python/RuntimeMeas/mult_split.py @@ -10,15 +10,16 @@ from dpsim.Event import Event import matplotlib -matplotlib.use('SVG') + +matplotlib.use("SVG") import matplotlib.pyplot as plt -name = 'WSCC-9bus_RX_dyn' -files = glob.glob('../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml') +name = "WSCC-9bus_RX_dyn" +files = glob.glob("../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml") threads = [1, 2, 4, 8, 16] sizes = range(1, 32) -scheduler = 'thread_level' +scheduler = "thread_level" reps = 5 for size in sizes: @@ -26,9 +27,18 @@ if not os.path.isfile(filename): system = dpsim.load_cim(name, files, frequency=60) if size > 1: - system.multiply(size-1) - sim = dpsim.Simulation(name, system, timestep=0.001, duration=0.5, init_steady_state=True, pbar=False, split_subnets=True, log_level=0) - sim.set_scheduler('sequential', out_measurement_file=filename) + system.multiply(size - 1) + sim = dpsim.Simulation( + name, + system, + timestep=0.001, + duration=0.5, + init_steady_state=True, + pbar=False, + split_subnets=True, + log_level=0, + ) + sim.set_scheduler("sequential", out_measurement_file=filename) sim.run() step_times = {} @@ -39,21 +49,30 @@ for i in range(0, reps): system = dpsim.load_cim(name, files, frequency=60) if size > 1: - system.multiply(size-1) - sim = dpsim.Simulation(name, system, timestep=0.001, duration=0.5, init_steady_state=True, pbar=False, split_subnets=True, log_level=0) + system.multiply(size - 1) + sim = dpsim.Simulation( + name, + system, + timestep=0.001, + duration=0.5, + init_steady_state=True, + pbar=False, + split_subnets=True, + log_level=0, + ) filename = "measurements_" + str(size) + ".txt" sim.set_scheduler(scheduler, threads=n, in_measurement_file=filename) sim.run() rep_times.append(sim.avg_step_time) - step_times[n].append(sum(rep_times)/len(rep_times)) + step_times[n].append(sum(rep_times) / len(rep_times)) for n in threads: - plt.plot(sizes, step_times[n], label=(str(n) + ' threads')) + plt.plot(sizes, step_times[n], label=(str(n) + " threads")) -plt.xlabel('System copies (with splitting)') -plt.ylabel('Wall time per step [s]') +plt.xlabel("System copies (with splitting)") +plt.ylabel("Wall time per step [s]") hostname = socket.gethostname() -plt.title('{} (using meas), on {}, {} reps average'.format(name, hostname, reps)) +plt.title("{} (using meas), on {}, {} reps average".format(name, hostname, reps)) plt.legend() -plt.savefig('mult_split_{}.svg'.format(hostname)) +plt.savefig("mult_split_{}.svg".format(hostname)) diff --git a/examples/Python/RuntimeMeas/sched_nthreads.py b/examples/Python/RuntimeMeas/sched_nthreads.py index 339eb72b8e..89abeece68 100644 --- a/examples/Python/RuntimeMeas/sched_nthreads.py +++ b/examples/Python/RuntimeMeas/sched_nthreads.py @@ -5,6 +5,7 @@ from meas_utils import * + def sched_nthreads(instance, threads, schedulers, size): times = {} sigmas = {} @@ -13,46 +14,51 @@ def sched_nthreads(instance, threads, schedulers, size): sigmas[scheduler] = [] for n in threads: sched_name, args = map_scheduler(scheduler, size) - if 'in_measurement_file' in list(args.keys()): + if "in_measurement_file" in list(args.keys()): do_meas(instance, size) - args['threads'] = n - avg, sigma = instance.do_sim(scheduler=sched_name, scheduler_args=args, size=size) + args["threads"] = n + avg, sigma = instance.do_sim( + scheduler=sched_name, scheduler_args=args, size=size + ) times[scheduler].append(avg) sigmas[scheduler].append(sigma) - return Measurement(instance, threads, 'threads', times, sigma=sigmas) + return Measurement(instance, threads, "threads", times, sigma=sigmas) + -if __name__ == '__main__': +if __name__ == "__main__": threads = range(1, 11) schedulers = [ -# 'sequential', - 'omp_level', - 'thread_level', - 'thread_level meas', - 'thread_list', - 'thread_list meas', + # 'sequential', + "omp_level", + "thread_level", + "thread_level meas", + "thread_list", + "thread_list meas", ] size = 1 - #size = 20 + # size = 20 - name = 'sched_nthreads' + name = "sched_nthreads" if len(sys.argv) > 1: name = sys.argv[1] - instance = SimInstance(name, glob.glob('../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml'), 60.0, 50) + instance = SimInstance( + name, glob.glob("../dpsim/examples/CIM/WSCC-09_RX_Dyn/*.xml"), 60.0, 50 + ) instance.sim_args = { - 'timestep': 0.0001, - 'duration': 0.1, - 'init_steady_state': False, - 'pbar': False, - 'split_subnets': True, - 'log_level': 0, + "timestep": 0.0001, + "duration": 0.1, + "init_steady_state": False, + "pbar": False, + "split_subnets": True, + "log_level": 0, } instance.copy_settings = { - 'decouple': False, - 'nodes': ['BUS5', 'BUS6', 'BUS8'], - 'resistance': 100, - 'inductance': 0.16, - 'capacitance': 1e-6, + "decouple": False, + "nodes": ["BUS5", "BUS6", "BUS8"], + "resistance": 100, + "inductance": 0.16, + "capacitance": 1e-6, } meas = sched_nthreads(instance, threads, schedulers, size) diff --git a/examples/conftest.py b/examples/conftest.py index edae686aa9..3b3b2f2332 100644 --- a/examples/conftest.py +++ b/examples/conftest.py @@ -2,23 +2,26 @@ import subprocess import pytest + def pytest_collect_file(parent, path): - if path.ext == ".yml" and path.basename.startswith("test_") and os.name == 'posix': + if path.ext == ".yml" and path.basename.startswith("test_") and os.name == "posix": return YamlFile.from_parent(parent, fspath=path) - if path.ext == '.ipynb': + if path.ext == ".ipynb": return JupyterNotebook.from_parent(parent, fspath=path) + def parse_test_params(item, spec): - if 'skip' in spec and spec['skip']: + if "skip" in spec and spec["skip"]: item.add_marker(pytest.mark.skip) - if 'xfail' in spec and spec['xfail']: + if "xfail" in spec and spec["xfail"]: item.add_marker(pytest.mark.xfail) + class YamlFile(pytest.File): def collect(self): - - # we need a yaml parser, e.g. PyYAML + # We need a yaml parser, e.g. PyYAML import yaml + raw = yaml.safe_load(self.fspath.open()) if not raw: @@ -27,49 +30,51 @@ def collect(self): for name, spec in sorted(raw.items()): yield YamlItem.from_parent(self, name=name, spec=spec) + class YamlItem(pytest.Item): def __init__(self, name, parent, spec): super().__init__(name, parent) self.spec = spec - if 'args' in spec: - self.args = spec['args'] + if "args" in spec: + self.args = spec["args"] else: - self.args = [ ] + self.args = [] - if 'shell' in spec: - self.shell = spec['shell'] + if "shell" in spec: + self.shell = spec["shell"] else: self.shell = False - if 'check' in spec: - self.check = spec['check'] + if "check" in spec: + self.check = spec["check"] else: self.check = True - if 'timeout' in spec: - self.timeout = spec['timeout'] + if "timeout" in spec: + self.timeout = spec["timeout"] else: self.timeout = 60 - if 'cwd' in spec: - self.cwd = spec['cwd'] + if "cwd" in spec: + self.cwd = spec["cwd"] else: - self.cwd = os.path.realpath(os.path.dirname(__file__) + '/..') + self.cwd = os.path.realpath(os.path.dirname(__file__) + "/..") parse_test_params(self, spec) - if 'cmd' in spec: - self.cmd = spec['cmd'] + if "cmd" in spec: + self.cmd = spec["cmd"] else: raise AttributeError('Test is missing mandatory "cmd" attribute') def runtest(self): - cp = subprocess.run([self.cmd] + self.args, - cwd = self.cwd, - shell = self.shell, - timeout = self.timeout, - check = True + cp = subprocess.run( + [self.cmd] + self.args, + cwd=self.cwd, + shell=self.shell, + timeout=self.timeout, + check=True, ) def repr_failure(self, excinfo): @@ -90,12 +95,12 @@ def collect(self): base = os.path.basename(self.name) name = os.path.splitext(base)[0] - spec = nb.metadata['tests'] if 'tests' in nb.metadata else {} + spec = nb.metadata["tests"] if "tests" in nb.metadata else {} yield JupyterNotebookExport.from_parent(self, name=name, spec=spec, nb=nb) -class JupyterNotebookExport(pytest.Item): +class JupyterNotebookExport(pytest.Item): def __init__(self, name, parent, spec, nb): super().__init__(name, parent) self.builddir = os.path.splitext(parent.name)[0] @@ -105,21 +110,22 @@ def __init__(self, name, parent, spec, nb): def runtest(self): from traitlets.config import Config - #from nbconvert import HTMLExporter + + # from nbconvert import HTMLExporter from nbconvert import MarkdownExporter from nbconvert.writers import FilesWriter c = Config() - c.FilesWriter.build_directory = 'outputs/' + self.builddir + c.FilesWriter.build_directory = "outputs/" + self.builddir # c.HTMLExporter.preprocessors = [ # 'nbconvert.preprocessors.ExecutePreprocessor', # 'nbconvert.preprocessors.ExtractOutputPreprocessor' # ] c.MarkdownExporter.preprocessors = [ - 'nbconvert.preprocessors.ExecutePreprocessor', - 'nbconvert.preprocessors.ExtractOutputPreprocessor' + "nbconvert.preprocessors.ExecutePreprocessor", + "nbconvert.preprocessors.ExtractOutputPreprocessor", ] - #exporter = HTMLExporter(config=c) + # exporter = HTMLExporter(config=c) exporter = MarkdownExporter(config=c) os.makedirs(c.FilesWriter.build_directory, exist_ok=True) diff --git a/examples/test_example.yml b/examples/test_example.yml index 561cfe3020..919ac193ed 100644 --- a/examples/test_example.yml +++ b/examples/test_example.yml @@ -14,4 +14,4 @@ example_test3: description: Returns non-zero return code cmd: exit 1 shell: True - xfail: True \ No newline at end of file + xfail: True diff --git a/examples/villas-deprecated/ShmemDistributedDirect.ipynb b/examples/villas-deprecated/ShmemDistributedDirect.ipynb index 7ae0ee4df0..950c8d5cea 100644 --- a/examples/villas-deprecated/ShmemDistributedDirect.ipynb +++ b/examples/villas-deprecated/ShmemDistributedDirect.ipynb @@ -41,7 +41,7 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = '../../../logs/ShmemDistributedRef/ShmemDistributedRef.csv'\n", + "log_name = \"../../../logs/ShmemDistributedRef/ShmemDistributedRef.csv\"\n", "ts_ref = rt.read_timeseries_dpsim(log_name)" ] }, @@ -53,9 +53,9 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", - "plt.plot(ts_ref['v1'].values.real)\n", - "plt.plot(ts_ref['v2'].values.real)\n", - "plt.plot(ts_ref['r12'].values.real)" + "plt.plot(ts_ref[\"v1\"].values.real)\n", + "plt.plot(ts_ref[\"v2\"].values.real)\n", + "plt.plot(ts_ref[\"r12\"].values.real)" ] }, { @@ -87,7 +87,7 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = '../../../logs/ShmemDistributedDirect_1/ShmemDistributedDirect_1.csv'\n", + "log_name = \"../../../logs/ShmemDistributedDirect_1/ShmemDistributedDirect_1.csv\"\n", "ts_direct1 = rt.read_timeseries_dpsim(log_name)" ] }, @@ -97,7 +97,7 @@ "metadata": {}, "outputs": [], "source": [ - "log_name = '../../../logs/ShmemDistributedDirect_2/ShmemDistributedDirect_2.csv'\n", + "log_name = \"../../../logs/ShmemDistributedDirect_2/ShmemDistributedDirect_2.csv\"\n", "ts_direct2 = rt.read_timeseries_dpsim(log_name)" ] }, @@ -107,10 +107,10 @@ "metadata": {}, "outputs": [], "source": [ - "plt.plot(ts_direct1['v1'].values.real)\n", - "plt.plot(ts_direct1['v2'].values.real)\n", - "plt.plot(ts_direct2['v2'].values.real)\n", - "plt.plot(ts_direct1['r12'].values.real)" + "plt.plot(ts_direct1[\"v1\"].values.real)\n", + "plt.plot(ts_direct1[\"v2\"].values.real)\n", + "plt.plot(ts_direct2[\"v2\"].values.real)\n", + "plt.plot(ts_direct1[\"r12\"].values.real)" ] }, { diff --git a/examples/villas-deprecated/ShmemExample.ipynb b/examples/villas-deprecated/ShmemExample.ipynb index a142bbe410..e30c7cbcd2 100644 --- a/examples/villas-deprecated/ShmemExample.ipynb +++ b/examples/villas-deprecated/ShmemExample.ipynb @@ -35,7 +35,7 @@ "metadata": {}, "outputs": [], "source": [ - "filename = '../../../logs/Shmem_Example/villas-pipe-out.log'\n", + "filename = \"../../../logs/Shmem_Example/villas-pipe-out.log\"\n", "ts = rt.read_timeseries_villas(filename)" ] }, diff --git a/examples/villas-deprecated/cigre-mv-pf-profiles-shmem.ipynb b/examples/villas-deprecated/cigre-mv-pf-profiles-shmem.ipynb index 715a70e7a4..de55ecf74b 100644 --- a/examples/villas-deprecated/cigre-mv-pf-profiles-shmem.ipynb +++ b/examples/villas-deprecated/cigre-mv-pf-profiles-shmem.ipynb @@ -23,18 +23,20 @@ "import requests\n", "import glob\n", "\n", + "\n", "def download_grid_data(name, url):\n", - " with open(name, 'wb') as out_file:\n", + " with open(name, \"wb\") as out_file:\n", " content = requests.get(url, stream=True).content\n", " out_file.write(content)\n", "\n", - "url = 'https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h'\n", - "filename = 'CIGRE-MV'\n", - "download_grid_data(filename+'_EQ.xml', url+'_EQ.xml')\n", - "download_grid_data(filename+'_TP.xml', url+'_TP.xml')\n", - "download_grid_data(filename+'_SV.xml', url+'_SV.xml')\n", "\n", - "files = glob.glob(filename+'_*.xml')\n", + "url = \"https://raw.githubusercontent.com/dpsim-simulator/cim-grid-data/master/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/Rootnet_FULL_NE_06J16h\"\n", + "filename = \"CIGRE-MV\"\n", + "download_grid_data(filename + \"_EQ.xml\", url + \"_EQ.xml\")\n", + "download_grid_data(filename + \"_TP.xml\", url + \"_TP.xml\")\n", + "download_grid_data(filename + \"_SV.xml\", url + \"_SV.xml\")\n", + "\n", + "files = glob.glob(filename + \"_*.xml\")\n", "print(files)" ] }, @@ -46,13 +48,37 @@ "source": [ "import os\n", "\n", - "profiles = ['Load_H_1','Load_H_3','Load_H_4','Load_H_5','Load_H_6','Load_H_8','Load_H_10','Load_H_11','Load_H_12','Load_H_14','Load_I_1','Load_I_3','Load_I_7','Load_I_9','Load_I_10','Load_I_12','Load_I_13','Load_I_14']\n", + "profiles = [\n", + " \"Load_H_1\",\n", + " \"Load_H_3\",\n", + " \"Load_H_4\",\n", + " \"Load_H_5\",\n", + " \"Load_H_6\",\n", + " \"Load_H_8\",\n", + " \"Load_H_10\",\n", + " \"Load_H_11\",\n", + " \"Load_H_12\",\n", + " \"Load_H_14\",\n", + " \"Load_I_1\",\n", + " \"Load_I_3\",\n", + " \"Load_I_7\",\n", + " \"Load_I_9\",\n", + " \"Load_I_10\",\n", + " \"Load_I_12\",\n", + " \"Load_I_13\",\n", + " \"Load_I_14\",\n", + "]\n", "for profile in profiles:\n", - " filename = './profiles/'+profile+'.csv'\n", + " filename = \"./profiles/\" + profile + \".csv\"\n", " os.makedirs(os.path.dirname(filename), exist_ok=True)\n", - " download_grid_data(filename, 'https://raw.githubusercontent.com/dpsim-simulator/example-profile-data/master/CIGRE_MV_NoTap/load_profiles/'+profile+'.csv')\n", - " \n", - "profile_files = glob.glob('profiles/Load*.csv')\n" + " download_grid_data(\n", + " filename,\n", + " \"https://raw.githubusercontent.com/dpsim-simulator/example-profile-data/master/CIGRE_MV_NoTap/load_profiles/\"\n", + " + profile\n", + " + \".csv\",\n", + " )\n", + "\n", + "profile_files = glob.glob(\"profiles/Load*.csv\")" ] }, { @@ -63,7 +89,7 @@ "source": [ "import pathlib\n", "\n", - "profile_path = str(pathlib.Path().resolve())+'/profiles/'\n", + "profile_path = str(pathlib.Path().resolve()) + \"/profiles/\"\n", "print(profile_path)" ] }, @@ -83,9 +109,11 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'CIGRE-MV-Profiles'\n", + "name = \"CIGRE-MV-Profiles\"\n", "reader = dpsimpy.CIMReader(name)\n", - "system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode)" + "system = reader.loadCIM(\n", + " 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode\n", + ")" ] }, { @@ -94,25 +122,25 @@ "metadata": {}, "outputs": [], "source": [ - "assignList = { }\n", - "assignList['LOAD-H-1'] = 'Load_H_1'\n", - "assignList['LOAD-H-3'] = 'Load_H_3'\n", - "assignList['LOAD-H-4'] = 'Load_H_4'\n", - "assignList['LOAD-H-5'] = 'Load_H_5'\n", - "assignList['LOAD-H-6'] = 'Load_H_6'\n", - "assignList['LOAD-H-8'] = 'Load_H_8'\n", - "assignList['LOAD-H-10'] = 'Load_H_10'\n", - "assignList['LOAD-H-11'] = 'Load_H_11'\n", - "assignList['LOAD-H-12'] = 'Load_H_12'\n", - "assignList['LOAD-H-14'] = 'Load_H_14'\n", - "assignList['LOAD-I-1'] = 'Load_I_1'\n", - "assignList['LOAD-I-3'] = 'Load_I_3'\n", - "assignList['LOAD-I-7'] = 'Load_I_7'\n", - "assignList['LOAD-I-9'] = 'Load_I_9'\n", - "assignList['LOAD-I-10'] = 'Load_I_10'\n", - "assignList['LOAD-I-12'] = 'Load_I_12'\n", - "assignList['LOAD-I-13'] = 'Load_I_13'\n", - "assignList['LOAD-I-14'] = 'Load_I_14'" + "assignList = {}\n", + "assignList[\"LOAD-H-1\"] = \"Load_H_1\"\n", + "assignList[\"LOAD-H-3\"] = \"Load_H_3\"\n", + "assignList[\"LOAD-H-4\"] = \"Load_H_4\"\n", + "assignList[\"LOAD-H-5\"] = \"Load_H_5\"\n", + "assignList[\"LOAD-H-6\"] = \"Load_H_6\"\n", + "assignList[\"LOAD-H-8\"] = \"Load_H_8\"\n", + "assignList[\"LOAD-H-10\"] = \"Load_H_10\"\n", + "assignList[\"LOAD-H-11\"] = \"Load_H_11\"\n", + "assignList[\"LOAD-H-12\"] = \"Load_H_12\"\n", + "assignList[\"LOAD-H-14\"] = \"Load_H_14\"\n", + "assignList[\"LOAD-I-1\"] = \"Load_I_1\"\n", + "assignList[\"LOAD-I-3\"] = \"Load_I_3\"\n", + "assignList[\"LOAD-I-7\"] = \"Load_I_7\"\n", + "assignList[\"LOAD-I-9\"] = \"Load_I_9\"\n", + "assignList[\"LOAD-I-10\"] = \"Load_I_10\"\n", + "assignList[\"LOAD-I-12\"] = \"Load_I_12\"\n", + "assignList[\"LOAD-I-13\"] = \"Load_I_13\"\n", + "assignList[\"LOAD-I-14\"] = \"Load_I_14\"" ] }, { @@ -122,7 +150,9 @@ "outputs": [], "source": [ "csvreader = dpsimpy.CSVReader(name, profile_path, assignList, dpsimpy.LogLevel.info)\n", - "csvreader.assignLoadProfile(system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS)" + "csvreader.assignLoadProfile(\n", + " system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS\n", + ")" ] }, { @@ -161,7 +191,7 @@ "outputs": [], "source": [ "obj_list = system.list_idobjects()\n", - "node_list = {k: v for k, v in obj_list.items() if v == 'SimNode >'}\n", + "node_list = {k: v for k, v in obj_list.items() if v == \"SimNode >\"}\n", "node_list" ] }, @@ -172,8 +202,13 @@ "outputs": [], "source": [ "for i in range(14):\n", - " sim.export_attribute(sim.get_idobj_attr('N'+str(i), 'v').derive_coeff(0,0).derive_mag(), 2*i)\n", - " sim.export_attribute(sim.get_idobj_attr('N'+str(i), 'v').derive_coeff(0,0).derive_phase(), 2*i+1)" + " sim.export_attribute(\n", + " sim.get_idobj_attr(\"N\" + str(i), \"v\").derive_coeff(0, 0).derive_mag(), 2 * i\n", + " )\n", + " sim.export_attribute(\n", + " sim.get_idobj_attr(\"N\" + str(i), \"v\").derive_coeff(0, 0).derive_phase(),\n", + " 2 * i + 1,\n", + " )" ] }, { @@ -183,7 +218,7 @@ "outputs": [], "source": [ "for node in system.nodes:\n", - " logger.log_attribute(node.name()+'.V', 'v', node)" + " logger.log_attribute(node.name() + \".V\", \"v\", node)" ] }, { diff --git a/examples/villas-deprecated/shmem-distributed-villas.py b/examples/villas-deprecated/shmem-distributed-villas.py index 5cee187cda..bcef5ec615 100644 --- a/examples/villas-deprecated/shmem-distributed-villas.py +++ b/examples/villas-deprecated/shmem-distributed-villas.py @@ -10,8 +10,8 @@ import villas.dataprocessing.readtools as rt import villas.dataprocessing.plottools as pt -def villas(): +def villas(): villas_conf = """ hugepages = 100 @@ -60,7 +60,7 @@ def villas(): with open("villas-node.conf", "w") as text_file: text_file.write("%s" % villas_conf) - os.system('villas-node villas-node.conf') + os.system("villas-node villas-node.conf") def dpsim0(): @@ -68,16 +68,16 @@ def dpsim0(): time_step = 0.001 final_time = 10 - n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [10]) - n2 = dpsimpy.dp.SimNode('n2', dpsimpy.PhaseType.Single, [5]) + n1 = dpsimpy.dp.SimNode("n1", dpsimpy.PhaseType.Single, [10]) + n2 = dpsimpy.dp.SimNode("n2", dpsimpy.PhaseType.Single, [5]) - evs = dpsimpy.dp.ph1.VoltageSource('v_intf', dpsimpy.LogLevel.debug) + evs = dpsimpy.dp.ph1.VoltageSource("v_intf", dpsimpy.LogLevel.debug) evs.set_parameters(complex(5, 0)) - vs1 = dpsimpy.dp.ph1.VoltageSource('vs_1', dpsimpy.LogLevel.debug) + vs1 = dpsimpy.dp.ph1.VoltageSource("vs_1", dpsimpy.LogLevel.debug) vs1.set_parameters(complex(10, 0)) - r12 = dpsimpy.dp.ph1.Resistor('r_12', dpsimpy.LogLevel.debug) + r12 = dpsimpy.dp.ph1.Resistor("r_12", dpsimpy.LogLevel.debug) r12.set_parameters(1) evs.connect([dpsimpy.dp.SimNode.gnd, n2]) @@ -86,24 +86,24 @@ def dpsim0(): sys = dpsimpy.SystemTopology(50, [n1, n2], [evs, vs1, r12]) - dpsimpy.Logger.set_log_dir('logs/' + sim_name) + dpsimpy.Logger.set_log_dir("logs/" + sim_name) logger = dpsimpy.Logger(sim_name) - logger.log_attribute('v1', 'v', n1) - logger.log_attribute('v2', 'v', n2) - logger.log_attribute('r12', 'i_intf', r12) - logger.log_attribute('ievs', 'i_intf', evs) - logger.log_attribute('vevs', 'v_intf', evs) + logger.log_attribute("v1", "v", n1) + logger.log_attribute("v2", "v", n2) + logger.log_attribute("r12", "i_intf", r12) + logger.log_attribute("ievs", "i_intf", evs) + logger.log_attribute("vevs", "v_intf", evs) sim = dpsimpy.RealTimeSimulation(sim_name) sim.set_system(sys) sim.set_time_step(time_step) sim.set_final_time(final_time) - intf = dpsimpyvillas.InterfaceShmem('/dpsim0-out', '/dpsim0-in') + intf = dpsimpyvillas.InterfaceShmem("/dpsim0-out", "/dpsim0-in") - sim.import_attribute(evs.attr('V_ref'), 0) - sim.export_attribute(evs.attr('i_intf').derive_coeff(0, 0), 0) + sim.import_attribute(evs.attr("V_ref"), 0) + sim.export_attribute(evs.attr("i_intf").derive_coeff(0, 0), 0) sim.add_interface(intf, True) sim.add_logger(logger) @@ -112,16 +112,17 @@ def dpsim0(): sim.run(1) + def dpsim1(): sim_name = "ShmemDistributed1" time_step = 0.001 final_time = 10 - n2 = dpsimpy.dp.SimNode('n2', dpsimpy.PhaseType.Single, [5]) + n2 = dpsimpy.dp.SimNode("n2", dpsimpy.PhaseType.Single, [5]) - ecs = dpsimpy.dp.ph1.CurrentSource('i_intf', dpsimpy.LogLevel.debug) + ecs = dpsimpy.dp.ph1.CurrentSource("i_intf", dpsimpy.LogLevel.debug) ecs.set_parameters(complex(5, 0)) - r02 = dpsimpy.dp.ph1.Resistor('r_02', dpsimpy.LogLevel.debug) + r02 = dpsimpy.dp.ph1.Resistor("r_02", dpsimpy.LogLevel.debug) r02.set_parameters(1) ecs.connect([dpsimpy.dp.SimNode.gnd, n2]) @@ -129,22 +130,24 @@ def dpsim1(): sys = dpsimpy.SystemTopology(50, [n2], [ecs, r02]) - dpsimpy.Logger.set_log_dir('logs/' + sim_name) + dpsimpy.Logger.set_log_dir("logs/" + sim_name) logger = dpsimpy.Logger(sim_name) - logger.log_attribute('v2', 'v', n2) - logger.log_attribute('r02', 'i_intf', r02) - logger.log_attribute('vecs', 'v_intf', ecs) - logger.log_attribute('iecs', 'i_intf', ecs) + logger.log_attribute("v2", "v", n2) + logger.log_attribute("r02", "i_intf", r02) + logger.log_attribute("vecs", "v_intf", ecs) + logger.log_attribute("iecs", "i_intf", ecs) sim = dpsimpy.RealTimeSimulation(sim_name) sim.set_system(sys) sim.set_time_step(time_step) sim.set_final_time(final_time) - intf = dpsimpyvillas.InterfaceShmem('/dpsim1-out', '/dpsim1-in') + intf = dpsimpyvillas.InterfaceShmem("/dpsim1-out", "/dpsim1-in") - sim.import_attribute(ecs.attr('I_ref'), 0) - sim.export_attribute(ecs.attr('v_intf').derive_coeff(0,0).derive_scaled(complex(-1,0)), 0) + sim.import_attribute(ecs.attr("I_ref"), 0) + sim.export_attribute( + ecs.attr("v_intf").derive_coeff(0, 0).derive_scaled(complex(-1, 0)), 0 + ) sim.add_interface(intf) sim.add_logger(logger) @@ -152,7 +155,7 @@ def dpsim1(): sim.run(1) -if __name__ == '__main__': +if __name__ == "__main__": queue = Queue() p_villas = Process(target=villas) p_dpsim0 = Process(target=dpsim0) @@ -165,6 +168,6 @@ def dpsim1(): p_dpsim0.join() p_dpsim1.join() - print('Both simulations have ended!') + print("Both simulations have ended!") p_villas.join() diff --git a/examples/villas-deprecated/test_shmem_cigre_mv_pf_profiles.py b/examples/villas-deprecated/test_shmem_cigre_mv_pf_profiles.py index 78f95728e9..e4681665bd 100644 --- a/examples/villas-deprecated/test_shmem_cigre_mv_pf_profiles.py +++ b/examples/villas-deprecated/test_shmem_cigre_mv_pf_profiles.py @@ -1,7 +1,13 @@ # To run this example, an MQTT broker is required -# docker run -it -p 1883:1883 -p 9001:9001 eclipse-mosquitto -# test message: mosquitto_pub -t 'test/topic' -m "test" -# get messages: mosquitto_sub -v -t '#' +# +# Start container: +# docker run -it -p 1883:1883 -p 9001:9001 eclipse-mosquitto +# +# Send message: +# mosquitto_pub -t 'test/topic' -m "test" +# +# Get messages: +# mosquitto_sub -v -t '#' import glob import sys @@ -18,97 +24,87 @@ base = os.path.splitext(os.path.basename(sys.argv[0]))[0] log = logging.getLogger(base) -def villas(intf, mqtt=False): - log_filename=datetime.now().strftime(f'{base}-villas-%y-%m-%d_%H_%M_%S.log') +def villas(intf, mqtt=False): + log_filename = datetime.now().strftime(f"{base}-villas-%y-%m-%d_%H_%M_%S.log") nodes = { - 'dpsim1': intf.get_config(), - 'file1': { - 'type': 'file', - - 'uri': f'{base}-results-%y-%m-%d_%H_%M_%S.csv' - } + "dpsim1": intf.get_config(), + "file1": {"type": "file", "uri": f"{base}-results-%y-%m-%d_%H_%M_%S.csv"}, } - paths = [ - { - 'in': 'dpsim1', - 'out': 'file1' - } - ] + paths = [{"in": "dpsim1", "out": "file1"}] - config = { - 'nodes': nodes, - 'paths': paths - } + config = {"nodes": nodes, "paths": paths} if mqtt: - nodes['broker1'] = { - 'type': 'mqtt', - - 'format': 'json', - 'host': '172.17.0.1', - - 'in': { - 'subscribe': '/powerflow-dpsim' - }, - 'out': { - 'publish': '/dpsim-powerflow' - } + nodes["broker1"] = { + "type": "mqtt", + "format": "json", + "host": "172.17.0.1", + "in": {"subscribe": "/powerflow-dpsim"}, + "out": {"publish": "/dpsim-powerflow"}, } - paths.append({ - 'in': 'dpsim1', - 'out': 'broker1', + paths.append( + { + "in": "dpsim1", + "out": "broker1", + "hooks": [{"type": "limit_rate", "rate": 50}], + } + ) - 'hooks': [ - { - 'type': 'limit_rate', - 'rate': 50 - } - ] - }) + log.info("VILLASnode config: \n%s", json.dumps(config, indent=2)) - log.info('VILLASnode config: \n%s', json.dumps(config, indent=2)) + return VILLASnode(config=config, log_filename=log_filename) - return VILLASnode(config=config, - log_filename=log_filename) def dpsim(): - name = 'CIGRE-MV-Profiles' - files = glob.glob('build/_deps/cim-data-src/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/*.xml') - log.info('CIM files: %s', files) + name = "CIGRE-MV-Profiles" + files = glob.glob( + "build/_deps/cim-data-src/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/*.xml" + ) + log.info("CIM files: %s", files) reader = dpsimpy.CIMReader(name) - system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode) - - csv_files = glob.glob('build/_deps/profile-data-src/CIGRE_MV_NoTap/load_profiles/')[0] - log.info('CSV files: %s', csv_files) + system = reader.loadCIM( + 50, + files, + dpsimpy.Domain.SP, + dpsimpy.PhaseType.Single, + dpsimpy.GeneratorType.PVNode, + ) + + csv_files = glob.glob("build/_deps/profile-data-src/CIGRE_MV_NoTap/load_profiles/")[ + 0 + ] + log.info("CSV files: %s", csv_files) assignList = { - 'LOAD-H-1': 'Load_H_1', - 'LOAD-H-3': 'Load_H_3', - 'LOAD-H-4': 'Load_H_4', - 'LOAD-H-5': 'Load_H_5', - 'LOAD-H-6': 'Load_H_6', - 'LOAD-H-8': 'Load_H_8', - 'LOAD-H-10': 'Load_H_10', - 'LOAD-H-11': 'Load_H_11', - 'LOAD-H-12': 'Load_H_12', - 'LOAD-H-14': 'Load_H_14', - 'LOAD-I-1': 'Load_I_1', - 'LOAD-I-3': 'Load_I_3', - 'LOAD-I-7': 'Load_I_7', - 'LOAD-I-9': 'Load_I_9', - 'LOAD-I-10': 'Load_I_10', - 'LOAD-I-12': 'Load_I_12', - 'LOAD-I-13': 'Load_I_13', - 'LOAD-I-14': 'Load_I_14' + "LOAD-H-1": "Load_H_1", + "LOAD-H-3": "Load_H_3", + "LOAD-H-4": "Load_H_4", + "LOAD-H-5": "Load_H_5", + "LOAD-H-6": "Load_H_6", + "LOAD-H-8": "Load_H_8", + "LOAD-H-10": "Load_H_10", + "LOAD-H-11": "Load_H_11", + "LOAD-H-12": "Load_H_12", + "LOAD-H-14": "Load_H_14", + "LOAD-I-1": "Load_I_1", + "LOAD-I-3": "Load_I_3", + "LOAD-I-7": "Load_I_7", + "LOAD-I-9": "Load_I_9", + "LOAD-I-10": "Load_I_10", + "LOAD-I-12": "Load_I_12", + "LOAD-I-13": "Load_I_13", + "LOAD-I-14": "Load_I_14", } csvreader = dpsimpy.CSVReader(name, csv_files, assignList, dpsimpy.LogLevel.info) - csvreader.assignLoadProfile(system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS) + csvreader.assignLoadProfile( + system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS + ) sim = dpsimpy.RealTimeSimulation(name) sim.set_system(system) @@ -124,25 +120,33 @@ def dpsim(): sim.add_interface(intf) obj_list = system.list_idobjects() - node_list = {k: v for k, v in obj_list.items() if v == 'SimNode >'} - log.info('Node list: %s', node_list) + node_list = { + k: v for k, v in obj_list.items() if v == "SimNode >" + } + log.info("Node list: %s", node_list) for i in range(15): - objname = 'N'+str(i) - sim.export_attribute(sim.get_idobj_attr(objname, 'v') - .derive_coeff(0,0) - .derive_mag(), (i*2)) - sim.export_attribute(sim.get_idobj_attr(objname, 'v') - .derive_coeff(0,0) - .derive_phase(), (i*2)+1) + objname = "N" + str(i) + sim.export_attribute( + sim.get_idobj_attr(objname, "v").derive_coeff(0, 0).derive_mag(), (i * 2) + ) + sim.export_attribute( + sim.get_idobj_attr(objname, "v").derive_coeff(0, 0).derive_phase(), + (i * 2) + 1, + ) for node in system.nodes: - logger.log_attribute(node.name()+'.V', 'v', node) + logger.log_attribute(node.name() + ".V", "v", node) return sim, intf + def test_shmem_cigre_mv_pf_profiles(): - logging.basicConfig(format='[%(asctime)s %(name)s %(levelname)s] %(message)s', datefmt='%H:%M:%S', level=logging.INFO) + logging.basicConfig( + format="[%(asctime)s %(name)s %(levelname)s] %(message)s", + datefmt="%H:%M:%S", + level=logging.INFO, + ) sim, intf = dpsim() node = villas(intf, mqtt=False) @@ -153,5 +157,6 @@ def test_shmem_cigre_mv_pf_profiles(): node.stop() -if __name__ == '__main__': + +if __name__ == "__main__": test_shmem_cigre_mv_pf_profiles() diff --git a/examples/villas-deprecated/test_shmem_distributed_direct.py b/examples/villas-deprecated/test_shmem_distributed_direct.py index d6e1d303f5..8568474bc4 100644 --- a/examples/villas-deprecated/test_shmem_distributed_direct.py +++ b/examples/villas-deprecated/test_shmem_distributed_direct.py @@ -2,51 +2,54 @@ import threading import dpsim + class Left(threading.Thread): def run(self): # Nodes gnd = dpsim.dp.Node.GND() - n1 = dpsim.dp.Node('n1') - n2 = dpsim.dp.Node('n2') + n1 = dpsim.dp.Node("n1") + n2 = dpsim.dp.Node("n2") - vs = dpsim.dp.ph1.VoltageSourceNorton('v_s', [n1, gnd], 10000+0j, 1) - evs = dpsim.dp.ph1.VoltageSource('v_ext', [n2, gnd], 0+0j) - l1 = dpsim.dp.ph1.Inductor('l_1', [n1, n2], 1e-3) + vs = dpsim.dp.ph1.VoltageSourceNorton("v_s", [n1, gnd], 10000 + 0j, 1) + evs = dpsim.dp.ph1.VoltageSource("v_ext", [n2, gnd], 0 + 0j) + l1 = dpsim.dp.ph1.Inductor("l_1", [n1, n2], 1e-3) - intf = dpsim.open_interface('/dpsim12', '/dpsim21', samplelen = 2) - intf.import_attribute(evs.attr('V_ref').derive_coeff(1, 0), 1) - intf.export_attribute(evs.attr('i_intf').derive_coeff(1, 0), 1) + intf = dpsim.open_interface("/dpsim12", "/dpsim21", samplelen=2) + intf.import_attribute(evs.attr("V_ref").derive_coeff(1, 0), 1) + intf.export_attribute(evs.attr("i_intf").derive_coeff(1, 0), 1) sys = dpsim.SystemTopology(50, [gnd, n1, n2], [evs, vs, l1]) - sim = dpsim.Simulation('shmem1', sys, duration = 1) + sim = dpsim.Simulation("shmem1", sys, duration=1) sim.add_interface(intf) - print('Starting simulation on left side') + print("Starting simulation on left side") sim.run() + class Right(threading.Thread): def run(self): # Nodes gnd = dpsim.dp.Node.GND() - n3 = dpsim.dp.Node('n3') + n3 = dpsim.dp.Node("n3") # Components - ecs = dpsim.dp.ph1.CurrentSource('i_ext', [n3, gnd], 0+0j) - r1 = dpsim.dp.ph1.Resistor('r_1', [n3, gnd], 1) + ecs = dpsim.dp.ph1.CurrentSource("i_ext", [n3, gnd], 0 + 0j) + r1 = dpsim.dp.ph1.Resistor("r_1", [n3, gnd], 1) - intf = dpsim.open_interface('/dpsim21', '/dpsim12', samplelen = 2) - intf.import_attribute(ecs.attr('I_ref').derive_coeff(1, 0), 1) - intf.export_attribute(r1.attr('v_intf').derive_coeff(1, 0), 1) + intf = dpsim.open_interface("/dpsim21", "/dpsim12", samplelen=2) + intf.import_attribute(ecs.attr("I_ref").derive_coeff(1, 0), 1) + intf.export_attribute(r1.attr("v_intf").derive_coeff(1, 0), 1) sys = dpsim.SystemTopology(50, [gnd, n3], [ecs, r1]) - sim = dpsim.Simulation('shmem2', sys, duration = 1) + sim = dpsim.Simulation("shmem2", sys, duration=1) sim.add_interface(intf) - print('Starting simulation on right side') + print("Starting simulation on right side") sim.run() + def test_ShmemDistributedDirect(): left_thread = Left() right_thread = Right() @@ -57,5 +60,6 @@ def test_ShmemDistributedDirect(): left_thread.join() right_thread.join() -if __name__ == '__main__': + +if __name__ == "__main__": test_ShmemDistributedDirect() diff --git a/examples/villas-deprecated/test_shmem_import_export.py b/examples/villas-deprecated/test_shmem_import_export.py index 9910be1628..d5597b32a5 100644 --- a/examples/villas-deprecated/test_shmem_import_export.py +++ b/examples/villas-deprecated/test_shmem_import_export.py @@ -15,48 +15,36 @@ base = os.path.splitext(os.path.basename(sys.argv[0]))[0] log = logging.getLogger(base) -def villas(intf): - log_filename=datetime.now().strftime(f'{base}-villas-%y-%m-%d_%H_%M_%S.log') +def villas(intf): + log_filename = datetime.now().strftime(f"{base}-villas-%y-%m-%d_%H_%M_%S.log") nodes = { - 'dpsim1': intf.get_config(), - 'file1': { - 'type': 'file', - 'uri': f'{base}-results-%y-%m-%d_%H_%M_%S.csv' - }, - 'sine' : { - 'type': 'signal', - 'signal': 'sine', - 'rate': 1, - 'frequency': 0.1, - 'amplitude': 50000, - 'offset': 100000 + "dpsim1": intf.get_config(), + "file1": {"type": "file", "uri": f"{base}-results-%y-%m-%d_%H_%M_%S.csv"}, + "sine": { + "type": "signal", + "signal": "sine", + "rate": 1, + "frequency": 0.1, + "amplitude": 50000, + "offset": 100000, }, } paths = [ - { - 'in': 'dpsim1', - 'out': 'file1' - }, - { - 'in': 'sine', - 'out': 'dpsim1', - 'hooks': [{'type':'print'}] - } + {"in": "dpsim1", "out": "file1"}, + {"in": "sine", "out": "dpsim1", "hooks": [{"type": "print"}]}, ] - config = { - 'nodes': nodes, - 'paths': paths - } - config['nodes']['dpsim1']['out']['hooks'] = [{'type':'print'}] + config = {"nodes": nodes, "paths": paths} + config["nodes"]["dpsim1"]["out"]["hooks"] = [{"type": "print"}] - log.info('VILLASnode config: \n%s', json.dumps(config, indent=2)) + log.info("VILLASnode config: \n%s", json.dumps(config, indent=2)) return VILLASnode(config=config, log_filename=log_filename) + def dpsim(): # Parameters V_nom = 20e3 @@ -65,23 +53,25 @@ def dpsim(): line_resistance = 0.05 line_inductance = 0.1 line_capacitance = 0.1e-6 - name = 'test_shmem_import_export' + name = "test_shmem_import_export" # Nodes and Components - n1 = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single) - n2 = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single) + n1 = dpsimpy.sp.SimNode("n1", dpsimpy.PhaseType.Single) + n2 = dpsimpy.sp.SimNode("n2", dpsimpy.PhaseType.Single) - extnet = dpsimpy.sp.ph1.NetworkInjection('Slack') + extnet = dpsimpy.sp.ph1.NetworkInjection("Slack") extnet.set_parameters(voltage_set_point=V_nom) extnet.set_base_voltage(V_nom) extnet.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD) - line = dpsimpy.sp.ph1.PiLine('PiLine') + line = dpsimpy.sp.ph1.PiLine("PiLine") line.set_parameters(R=line_resistance, L=line_inductance, C=line_capacitance) line.set_base_voltage(V_nom) - load = dpsimpy.sp.ph1.Load('Load') - load.set_parameters(active_power=p_load_nom, reactive_power=q_load_nom, nominal_voltage=V_nom) + load = dpsimpy.sp.ph1.Load("Load") + load.set_parameters( + active_power=p_load_nom, reactive_power=q_load_nom, nominal_voltage=V_nom + ) load.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PQ) extnet.connect([n1]) @@ -99,18 +89,23 @@ def dpsim(): logger = dpsimpy.Logger(name) sim.add_logger(logger) - sim.log_attribute('n1.v', n1.attr('v')) - sim.log_attribute('n2.v', n2.attr('v')) + sim.log_attribute("n1.v", n1.attr("v")) + sim.log_attribute("n2.v", n2.attr("v")) intf = dpsimpyvillas.InterfaceShmem() sim.add_interface(intf) - sim.import_attribute(load.attr('P'), 0) - sim.export_attribute(n2.attr('v').derive_coeff(0,0).derive_mag(), 0) + sim.import_attribute(load.attr("P"), 0) + sim.export_attribute(n2.attr("v").derive_coeff(0, 0).derive_mag(), 0) return sim, intf + def test_shmem_import_export(): - logging.basicConfig(format='[%(asctime)s %(name)s %(levelname)s] %(message)s', datefmt='%H:%M:%S', level=logging.INFO) + logging.basicConfig( + format="[%(asctime)s %(name)s %(levelname)s] %(message)s", + datefmt="%H:%M:%S", + level=logging.INFO, + ) sim, intf = dpsim() node = villas(intf) @@ -121,5 +116,6 @@ def test_shmem_import_export(): node.stop() -if __name__ == '__main__': + +if __name__ == "__main__": test_shmem_import_export() diff --git a/examples/villas/docker-compose-dpsim-mqtt/docker-compose.yml b/examples/villas/docker-compose-dpsim-mqtt/docker-compose.yml index fab32160f2..a8406e553d 100644 --- a/examples/villas/docker-compose-dpsim-mqtt/docker-compose.yml +++ b/examples/villas/docker-compose-dpsim-mqtt/docker-compose.yml @@ -4,7 +4,7 @@ services: context: ../../../../ #dpsim top-level folder dockerfile: packaging/Docker/Dockerfile.dev environment: - PYTHONPATH: /dpsim/build:/dpsim/build/Source/Python:/dpsim/Source/Python + PYTHONPATH: /dpsim/build:/dpsim/build/Source/Python:/dpsim/Source/Python ports: - "8888:8888" volumes: diff --git a/examples/villas/dpsim-file.py b/examples/villas/dpsim-file.py index cf7b157d6e..39160d6b16 100644 --- a/examples/villas/dpsim-file.py +++ b/examples/villas/dpsim-file.py @@ -1,5 +1,7 @@ # This example demonstrates the export of values calculated by dpsim to a file using the VILLASnode interface +import json + import dpsimpy import dpsimpyvillas @@ -7,16 +9,16 @@ time_step = 0.01 final_time = 10 -n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [10]) -n2 = dpsimpy.dp.SimNode('n2', dpsimpy.PhaseType.Single, [5]) +n1 = dpsimpy.dp.SimNode("n1", dpsimpy.PhaseType.Single, [10]) +n2 = dpsimpy.dp.SimNode("n2", dpsimpy.PhaseType.Single, [5]) -evs = dpsimpy.dp.ph1.VoltageSource('v_intf', dpsimpy.LogLevel.debug) +evs = dpsimpy.dp.ph1.VoltageSource("v_intf", dpsimpy.LogLevel.debug) evs.set_parameters(complex(5, 0)) -vs1 = dpsimpy.dp.ph1.VoltageSource('vs_1', dpsimpy.LogLevel.debug) +vs1 = dpsimpy.dp.ph1.VoltageSource("vs_1", dpsimpy.LogLevel.debug) vs1.set_parameters(complex(10, 0)) -r12 = dpsimpy.dp.ph1.Resistor('r_12', dpsimpy.LogLevel.debug) +r12 = dpsimpy.dp.ph1.Resistor("r_12", dpsimpy.LogLevel.debug) r12.set_parameters(1) evs.connect([dpsimpy.dp.SimNode.gnd, n2]) @@ -25,37 +27,35 @@ sys = dpsimpy.SystemTopology(50, [n1, n2], [evs, vs1, r12]) -dpsimpy.Logger.set_log_dir('logs/' + sim_name) +dpsimpy.Logger.set_log_dir("logs/" + sim_name) logger = dpsimpy.Logger(sim_name) -logger.log_attribute('v1', 'v', n1) -logger.log_attribute('v2', 'v', n2) -logger.log_attribute('r12', 'i_intf', r12) -logger.log_attribute('ievs', 'i_intf', evs) -logger.log_attribute('vevs', 'v_intf', evs) +logger.log_attribute("v1", "v", n1) +logger.log_attribute("v2", "v", n2) +logger.log_attribute("r12", "i_intf", r12) +logger.log_attribute("ievs", "i_intf", evs) +logger.log_attribute("vevs", "v_intf", evs) sim = dpsimpy.RealTimeSimulation(sim_name) sim.set_system(sys) sim.set_time_step(time_step) sim.set_final_time(final_time) -file_config = '''{ - "type": "file", - "format": "csv", - "uri": "logs/output.csv", - "out": { - "flush": true - } -}''' +intf_config = { + "type": "file", + "format": "csv", + "uri": "logs/output.csv", + "out": {"flush": True}, +} -intf = dpsimpyvillas.InterfaceVillas(file_config, name='dpsim-file') -intf.export_attribute(evs.attr('i_intf').derive_coeff(0, 0), 0) +intf = dpsimpyvillas.InterfaceVillas(name="dpsim-file", config=json.dumps(intf_config)) +intf.export_attribute(evs.attr("i_intf").derive_coeff(0, 0), 0) sim.add_interface(intf) -#sim.import_attribute('v_intf', 'V_ref', 0) +# sim.import_attribute('v_intf', 'V_ref', 0) sim.add_logger(logger) evs.set_intf_current([[complex(5, 0)]]) -sim.run(1) \ No newline at end of file +sim.run(1) diff --git a/examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py b/examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py index 8b5ef2c850..ea25edffee 100644 --- a/examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py +++ b/examples/villas/dpsim-mqtt-cigre-mv-pf-profiles.py @@ -4,69 +4,76 @@ import logging import os import sys +import json import dpsimpy import dpsimpyvillas -# setup -name = 'CIGRE-MV-Profiles' +# Setup +name = "CIGRE-MV-Profiles" time_step = 1 final_time = 30 -# setup stdout logger +# Setup stdout logger base = os.path.splitext(os.path.basename(sys.argv[0]))[0] log = logging.getLogger(base) -# read topology from CIM -files = glob.glob('build/_deps/cim-data-src/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/*.xml') # downloaded by CMake -log.info('CIM files: %s', files) +# Read topology from CIM +files = glob.glob( + "build/_deps/cim-data-src/CIGRE_MV/NEPLAN/CIGRE_MV_no_tapchanger_With_LoadFlow_Results/*.xml" +) # Downloaded by CMake +log.info("CIM files: %s", files) reader = dpsimpy.CIMReader(name) -system = reader.loadCIM(50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode) +system = reader.loadCIM( + 50, files, dpsimpy.Domain.SP, dpsimpy.PhaseType.Single, dpsimpy.GeneratorType.PVNode +) -# map from CSV to simulation names +# Map from CSV to simulation names assignList = { - 'LOAD-H-1': 'Load_H_1', - 'LOAD-H-3': 'Load_H_3', - 'LOAD-H-4': 'Load_H_4', - 'LOAD-H-5': 'Load_H_5', - 'LOAD-H-6': 'Load_H_6', - 'LOAD-H-8': 'Load_H_8', - 'LOAD-H-10': 'Load_H_10', - 'LOAD-H-11': 'Load_H_11', - 'LOAD-H-12': 'Load_H_12', - 'LOAD-H-14': 'Load_H_14', - 'LOAD-I-1': 'Load_I_1', - 'LOAD-I-3': 'Load_I_3', - 'LOAD-I-7': 'Load_I_7', - 'LOAD-I-9': 'Load_I_9', - 'LOAD-I-10': 'Load_I_10', - 'LOAD-I-12': 'Load_I_12', - 'LOAD-I-13': 'Load_I_13', - 'LOAD-I-14': 'Load_I_14' + "LOAD-H-1": "Load_H_1", + "LOAD-H-3": "Load_H_3", + "LOAD-H-4": "Load_H_4", + "LOAD-H-5": "Load_H_5", + "LOAD-H-6": "Load_H_6", + "LOAD-H-8": "Load_H_8", + "LOAD-H-10": "Load_H_10", + "LOAD-H-11": "Load_H_11", + "LOAD-H-12": "Load_H_12", + "LOAD-H-14": "Load_H_14", + "LOAD-I-1": "Load_I_1", + "LOAD-I-3": "Load_I_3", + "LOAD-I-7": "Load_I_7", + "LOAD-I-9": "Load_I_9", + "LOAD-I-10": "Load_I_10", + "LOAD-I-12": "Load_I_12", + "LOAD-I-13": "Load_I_13", + "LOAD-I-14": "Load_I_14", } -# read profiles from CSV -csv_files = 'build/_deps/profile-data-src/CIGRE_MV_NoTap/load_profiles/' -log.info('CSV files: %s', csv_files) +# Read profiles from CSV +csv_files = "build/_deps/profile-data-src/CIGRE_MV_NoTap/load_profiles/" +log.info("CSV files: %s", csv_files) csvreader = dpsimpy.CSVReader(name, csv_files, assignList, dpsimpy.LogLevel.info) -csvreader.assignLoadProfile(system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS) +csvreader.assignLoadProfile( + system, 0, 1, 300, dpsimpy.CSVReaderMode.MANUAL, dpsimpy.CSVReaderFormat.SECONDS +) -# instantiate logger +# Instantiate logger logger = dpsimpy.Logger(name) # setup VILLASnode -intf_mqtt = dpsimpyvillas.InterfaceVillas(name='MQTT', config='''{ +intf_mqtt_config = { "type": "mqtt", "host": "mqtt", - "in": { - "subscribe": "mqtt-dpsim" - }, - "out": { - "publish": "dpsim-mqtt" - } -}''') + "in": {"subscribe": "mqtt-dpsim"}, + "out": {"publish": "dpsim-mqtt"}, +} + +intf_mqtt = dpsimpyvillas.InterfaceVillas( + name="MQTT", config=json.dumps(intf_mqtt_config) +) -# setup simulation +# Setup simulation sim = dpsimpy.RealTimeSimulation(name) sim.set_system(system) sim.set_domain(dpsimpy.Domain.SP) @@ -76,20 +83,18 @@ sim.add_logger(logger) sim.add_interface(intf_mqtt) -# setup exports +# Setup exports for i in range(15): - objname = 'N'+str(i) - intf_mqtt.export_attribute(sim \ - .get_idobj_attr(objname, 'v') \ - .derive_coeff(0,0) \ - .derive_mag(), 2*i) - intf_mqtt.export_attribute(sim \ - .get_idobj_attr(objname, 'v') \ - .derive_coeff(0,0) \ - .derive_phase(), 2*i+1) + objname = "N" + str(i) + intf_mqtt.export_attribute( + sim.get_idobj_attr(objname, "v").derive_coeff(0, 0).derive_mag(), 2 * i + ) + intf_mqtt.export_attribute( + sim.get_idobj_attr(objname, "v").derive_coeff(0, 0).derive_phase(), 2 * i + 1 + ) -# log exports +# Log exports for node in system.nodes: - sim.log_idobj_attribute(node.name(), 'v') + sim.log_idobj_attribute(node.name(), "v") sim.run(1) diff --git a/examples/villas/dpsim-mqtt-import-export-MIMO.py b/examples/villas/dpsim-mqtt-import-export-MIMO.py index 1e37e46b86..4e73896e3f 100644 --- a/examples/villas/dpsim-mqtt-import-export-MIMO.py +++ b/examples/villas/dpsim-mqtt-import-export-MIMO.py @@ -1,5 +1,5 @@ # This example attempts to read a sine signal generated by VILLASnode via a MQTT connection as well as a shared memory connection. -# dpsim then exports several values over these connections which should be read by VILLASnode and written to a file. +# DPsim then exports several values over these connections which should be read by VILLASnode and written to a file. # Due to problems with the shared memory node in VILLAS, this example currently does not run correctly! @@ -18,97 +18,61 @@ base = os.path.splitext(os.path.basename(sys.argv[0]))[0] log = logging.getLogger(base) -def villas(): - log_filename=datetime.now().strftime(f'{base}-villas-%y-%m-%d_%H_%M_%S.log') +def villas(): + log_filename = datetime.now().strftime(f"{base}-villas-%y-%m-%d_%H_%M_%S.log") nodes = { - 'mqtt': { - 'type': 'mqtt', - 'format': 'json', - 'host': 'mqtt', - 'in': { - 'subscribe': '/dpsim-mqtt', - 'signals': [ - { - 'name': 'v1', - 'type': 'complex' - }, - { - 'name': 'v2_mag', - 'type': 'float' - } - ] + "mqtt": { + "type": "mqtt", + "format": "json", + "host": "mqtt", + "in": { + "subscribe": "/dpsim-mqtt", + "signals": [ + {"name": "v1", "type": "complex"}, + {"name": "v2_mag", "type": "float"}, + ], }, - 'out': { - 'publish': '/mqtt-dpsim' - } + "out": {"publish": "/mqtt-dpsim"}, }, - 'shmem': { - 'type': 'shmem', - 'in': { - 'name': '/dpsim-shmem', - 'signals': [ - { - 'name': 'v1', - 'type': 'complex' - }, - { - 'name': 'v2_mag', - 'type': 'float' - } - ] + "shmem": { + "type": "shmem", + "in": { + "name": "/dpsim-shmem", + "signals": [ + {"name": "v1", "type": "complex"}, + {"name": "v2_mag", "type": "float"}, + ], }, - 'out': { - 'name': '/shmem-dpsim' - } - }, - 'file1': { - 'type': 'file', - 'uri': f'{base}-results-%y-%m-%d_%H_%M_%S.csv' - }, - 'file2': { - 'type': 'file', - 'uri': f'{base}-results-%y-%m-%d_%H_%M_%S_2.csv' + "out": {"name": "/shmem-dpsim"}, }, - 'sine' : { - 'type': 'signal', - 'signal': 'sine', - 'rate': 10, - 'frequency': 0.1, - 'amplitude': 50000, - 'offset': 100000 + "file1": {"type": "file", "uri": f"{base}-results-%y-%m-%d_%H_%M_%S.csv"}, + "file2": {"type": "file", "uri": f"{base}-results-%y-%m-%d_%H_%M_%S_2.csv"}, + "sine": { + "type": "signal", + "signal": "sine", + "rate": 10, + "frequency": 0.1, + "amplitude": 50000, + "offset": 100000, }, } paths = [ - { - 'in': 'mqtt', - 'out': 'file1', - 'hooks': [{'type':'print'}] - }, - { - 'in': 'shmem', - 'out': 'file2', - 'hooks': [{'type':'print'}] - }, - { - 'in': 'sine', - 'out': ['mqtt', 'shmem'], - 'hooks': [{'type':'print'}] - }, + {"in": "mqtt", "out": "file1", "hooks": [{"type": "print"}]}, + {"in": "shmem", "out": "file2", "hooks": [{"type": "print"}]}, + {"in": "sine", "out": ["mqtt", "shmem"], "hooks": [{"type": "print"}]}, ] - config = { - 'nodes': nodes, - 'paths': paths - } - config['nodes']['mqtt']['out']['hooks'] = [{'type':'print'}] + config = {"nodes": nodes, "paths": paths} + config["nodes"]["mqtt"]["out"]["hooks"] = [{"type": "print"}] - log.info('VILLASnode config: \n%s', json.dumps(config, indent=2)) + log.info("VILLASnode config: \n%s", json.dumps(config, indent=2)) return VILLASnode(config=config, log_filename=log_filename) + def dpsim(): # Parameters V_nom = 20e3 @@ -117,23 +81,25 @@ def dpsim(): line_resistance = 0.05 line_inductance = 0.1 line_capacitance = 0.1e-6 - name = 'dpsim_mqtt_import_export' + name = "dpsim_mqtt_import_export" # Nodes and Components - n1 = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single) - n2 = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single) + n1 = dpsimpy.sp.SimNode("n1", dpsimpy.PhaseType.Single) + n2 = dpsimpy.sp.SimNode("n2", dpsimpy.PhaseType.Single) - extnet = dpsimpy.sp.ph1.NetworkInjection('Slack') + extnet = dpsimpy.sp.ph1.NetworkInjection("Slack") extnet.set_parameters(voltage_set_point=V_nom) extnet.set_base_voltage(V_nom) extnet.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD) - line = dpsimpy.sp.ph1.PiLine('PiLine') + line = dpsimpy.sp.ph1.PiLine("PiLine") line.set_parameters(R=line_resistance, L=line_inductance, C=line_capacitance) line.set_base_voltage(V_nom) - load = dpsimpy.sp.ph1.Load('Load') - load.set_parameters(active_power=p_load_nom, reactive_power=q_load_nom, nominal_voltage=V_nom) + load = dpsimpy.sp.ph1.Load("Load") + load.set_parameters( + active_power=p_load_nom, reactive_power=q_load_nom, nominal_voltage=V_nom + ) load.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PQ) extnet.connect([n1]) @@ -148,57 +114,65 @@ def dpsim(): sim.set_time_step(0.1) sim.set_final_time(10) sim.do_init_from_nodes_and_terminals(False) - + logger = dpsimpy.Logger(name) sim.add_logger(logger) - sim.log_attribute('n1.v', n1.attr('v')) - sim.log_attribute('n2.v', n1.attr('v')) + sim.log_attribute("n1.v", n1.attr("v")) + sim.log_attribute("n2.v", n1.attr("v")) intf_config = { "type": "mqtt", "format": "json", "host": "mqtt", - "in": { - "subscribe": "/mqtt-dpsim" - }, - "out": { - "publish": "/dpsim-mqtt" - } + "in": {"subscribe": "/mqtt-dpsim"}, + "out": {"publish": "/dpsim-mqtt"}, } intf_config_2 = { "type": "shmem", - "in": { - "name": "/shmem-dpsim" - }, - "out": { - "name": "/dpsim-shmem" - } + "in": {"name": "/shmem-dpsim"}, + "out": {"name": "/dpsim-shmem"}, } - intf = dpsimpyvillas.InterfaceVillas(name="dpsim-mqtt", config=intf_config) + intf = dpsimpyvillas.InterfaceVillas( + name="dpsim-mqtt", config=json.dumps(intf_config) + ) sim.add_interface(intf) - intf2 = dpsimpyvillas.InterfaceVillas(name="dpsim-shmem", config=intf_config_2) + intf2 = dpsimpyvillas.InterfaceVillas( + name="dpsim-shmem", config=json.dumps(intf_config_2) + ) sim.add_interface(intf2) - intf.import_attribute(load.attr('P'), 0) - intf.export_attribute(n1.attr('v').derive_coeff(0,0), 0) - intf.export_attribute(n2.attr('v').derive_coeff(0,0).derive_mag(), 1) - intf2.import_attribute(load.attr('Q'), 0) - intf2.export_attribute(n1.attr('v').derive_coeff(0,0), 0) - intf2.export_attribute(n2.attr('v').derive_coeff(0,0).derive_mag(), 1) - + intf.import_attribute(load.attr("P"), 0) + intf.export_attribute(n1.attr("v").derive_coeff(0, 0), 0) + intf.export_attribute(n2.attr("v").derive_coeff(0, 0).derive_mag(), 1) + intf2.import_attribute(load.attr("Q"), 0) + intf2.export_attribute(n1.attr("v").derive_coeff(0, 0), 0) + intf2.export_attribute(n2.attr("v").derive_coeff(0, 0).derive_mag(), 1) + return sim, intf, intf2 -def test_shmem_import_export(): - logging.basicConfig(format='[%(asctime)s %(name)s %(levelname)s] %(message)s', datefmt='%H:%M:%S', level=logging.INFO) - sim, intf, intf2 = dpsim() #intf needs to be extracted from the dpsim-function since the interface object gets deleted otherwise leading to SegFault when starting the simulation +def test_shmem_import_export(): + logging.basicConfig( + format="[%(asctime)s %(name)s %(levelname)s] %(message)s", + datefmt="%H:%M:%S", + level=logging.INFO, + ) + + ( + sim, + intf, + intf2, + ) = ( + dpsim() + ) # intf needs to be extracted from the dpsim-function since the interface object gets deleted otherwise leading to SegFault when starting the simulation node = villas() node.start() sim.run(1) node.stop() -if __name__ == '__main__': - test_shmem_import_export() \ No newline at end of file + +if __name__ == "__main__": + test_shmem_import_export() diff --git a/examples/villas/dpsim-mqtt-import-export.py b/examples/villas/dpsim-mqtt-import-export.py index 8367852c33..28ee471a2d 100644 --- a/examples/villas/dpsim-mqtt-import-export.py +++ b/examples/villas/dpsim-mqtt-import-export.py @@ -16,69 +16,48 @@ base = os.path.splitext(os.path.basename(sys.argv[0]))[0] log = logging.getLogger(base) -def villas(): - log_filename=datetime.now().strftime(f'{base}-villas-%y-%m-%d_%H_%M_%S.log') +def villas(): + log_filename = datetime.now().strftime(f"{base}-villas-%y-%m-%d_%H_%M_%S.log") nodes = { - 'mqtt': { - 'type': 'mqtt', - 'format': 'json', - 'host': 'mqtt', - 'in': { - 'subscribe': '/dpsim-mqtt', - 'signals': [ - { - 'name': 'v1', - 'type': 'complex' - }, - { - 'name': 'v2_mag', - 'type': 'float' - } - ] + "mqtt": { + "type": "mqtt", + "format": "json", + "host": "mqtt", + "in": { + "subscribe": "/dpsim-mqtt", + "signals": [ + {"name": "v1", "type": "complex"}, + {"name": "v2_mag", "type": "float"}, + ], }, - 'out': { - 'publish': '/mqtt-dpsim' - } - }, - 'file1': { - 'type': 'file', - 'uri': f'{base}-results-%y-%m-%d_%H_%M_%S.csv' + "out": {"publish": "/mqtt-dpsim"}, }, - 'sine' : { - 'type': 'signal', - 'signal': 'sine', - 'rate': 10, - 'frequency': 0.1, - 'amplitude': 50000, - 'offset': 100000 + "file1": {"type": "file", "uri": f"{base}-results-%y-%m-%d_%H_%M_%S.csv"}, + "sine": { + "type": "signal", + "signal": "sine", + "rate": 10, + "frequency": 0.1, + "amplitude": 50000, + "offset": 100000, }, } paths = [ - { - 'in': 'mqtt', - 'out': 'file1', - 'hooks': [{'type':'print'}] - }, - { - 'in': 'sine', - 'out': 'mqtt', - 'hooks': [{'type':'print'}] - } + {"in": "mqtt", "out": "file1", "hooks": [{"type": "print"}]}, + {"in": "sine", "out": "mqtt", "hooks": [{"type": "print"}]}, ] - config = { - 'nodes': nodes, - 'paths': paths - } - config['nodes']['mqtt']['out']['hooks'] = [{'type':'print'}] + config = {"nodes": nodes, "paths": paths} + config["nodes"]["mqtt"]["out"]["hooks"] = [{"type": "print"}] - log.info('VILLASnode config: \n%s', json.dumps(config, indent=2)) + log.info("VILLASnode config: \n%s", json.dumps(config, indent=2)) return VILLASnode(config=config, log_filename=log_filename) + def dpsim(): # Parameters V_nom = 20e3 @@ -87,23 +66,25 @@ def dpsim(): line_resistance = 0.05 line_inductance = 0.1 line_capacitance = 0.1e-6 - name = 'dpsim_mqtt_import_export' + name = "dpsim_mqtt_import_export" # Nodes and Components - n1 = dpsimpy.sp.SimNode('n1', dpsimpy.PhaseType.Single) - n2 = dpsimpy.sp.SimNode('n2', dpsimpy.PhaseType.Single) + n1 = dpsimpy.sp.SimNode("n1", dpsimpy.PhaseType.Single) + n2 = dpsimpy.sp.SimNode("n2", dpsimpy.PhaseType.Single) - extnet = dpsimpy.sp.ph1.NetworkInjection('Slack') + extnet = dpsimpy.sp.ph1.NetworkInjection("Slack") extnet.set_parameters(voltage_set_point=V_nom) extnet.set_base_voltage(V_nom) extnet.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD) - line = dpsimpy.sp.ph1.PiLine('PiLine') + line = dpsimpy.sp.ph1.PiLine("PiLine") line.set_parameters(R=line_resistance, L=line_inductance, C=line_capacitance) line.set_base_voltage(V_nom) - load = dpsimpy.sp.ph1.Load('Load') - load.set_parameters(active_power=p_load_nom, reactive_power=q_load_nom, nominal_voltage=V_nom) + load = dpsimpy.sp.ph1.Load("Load") + load.set_parameters( + active_power=p_load_nom, reactive_power=q_load_nom, nominal_voltage=V_nom + ) load.modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PQ) extnet.connect([n1]) @@ -121,38 +102,47 @@ def dpsim(): logger = dpsimpy.Logger(name) sim.add_logger(logger) - sim.log_attribute('n1.v', n1.attr('v')) - sim.log_attribute('n2.v', n2.attr('v')) + sim.log_attribute("n1.v", n1.attr("v")) + sim.log_attribute("n2.v", n2.attr("v")) intf_config = { "type": "mqtt", "format": "json", "host": "mqtt", - "in": { - "subscribe": "/mqtt-dpsim" - }, - "out": { - "publish": "/dpsim-mqtt" - } + "in": {"subscribe": "/mqtt-dpsim"}, + "out": {"publish": "/dpsim-mqtt"}, } - intf = dpsimpyvillas.InterfaceVillas(name="dpsim-mqtt", config=intf_config) - intf.import_attribute(load.attr('P'), 0) - intf.export_attribute(n1.attr('v').derive_coeff(0,0), 0) - intf.export_attribute(n2.attr('v').derive_coeff(0,0).derive_mag(), 1) + intf = dpsimpyvillas.InterfaceVillas( + name="dpsim-mqtt", config=json.dumps(intf_config) + ) + intf.import_attribute(load.attr("P"), 0) + intf.export_attribute(n1.attr("v").derive_coeff(0, 0), 0) + intf.export_attribute(n2.attr("v").derive_coeff(0, 0).derive_mag(), 1) sim.add_interface(intf) return sim, intf -def test_shmem_import_export(): - logging.basicConfig(format='[%(asctime)s %(name)s %(levelname)s] %(message)s', datefmt='%H:%M:%S', level=logging.INFO) - sim, intf = dpsim() #intf needs to be extracted from the dpsim-function since the interface object gets deleted otherwise leading to SegFault when starting the simulation +def test_shmem_import_export(): + logging.basicConfig( + format="[%(asctime)s %(name)s %(levelname)s] %(message)s", + datefmt="%H:%M:%S", + level=logging.INFO, + ) + + ( + sim, + intf, + ) = ( + dpsim() + ) # intf needs to be extracted from the dpsim-function since the interface object gets deleted otherwise leading to SegFault when starting the simulation node = villas() node.start() sim.run(1) node.stop() -if __name__ == '__main__': + +if __name__ == "__main__": test_shmem_import_export() diff --git a/examples/villas/dpsim-mqtt-producer.py b/examples/villas/dpsim-mqtt-producer.py index 4cd44d7a6b..5e49d93afa 100644 --- a/examples/villas/dpsim-mqtt-producer.py +++ b/examples/villas/dpsim-mqtt-producer.py @@ -2,26 +2,28 @@ import json import time + def build_message(sequence, v_ref): - ts_field = {"origin":[int(elem) for elem in str(time.time()).split('.')]} + ts_field = {"origin": [int(elem) for elem in str(time.time()).split(".")]} data_field = [v_ref] message = {"ts": ts_field, "sequence": sequence, "data": data_field} return "[" + json.dumps(message) + "]" -if __name__ == '__main__': + +if __name__ == "__main__": time.sleep(10) seq = 0 T_s = 0.01 tf = 10.0 - num_samples = int(tf/T_s) + 2 + num_samples = int(tf / T_s) + 2 for n in range(0, num_samples): - if n < int(num_samples/2): - m_v_ref = {"real":5.0, "imag":0.0} + if n < int(num_samples / 2): + m_v_ref = {"real": 5.0, "imag": 0.0} else: - m_v_ref = {"real":7.0, "imag":0.0} + m_v_ref = {"real": 7.0, "imag": 0.0} m_message = build_message(sequence=seq, v_ref=m_v_ref) print(m_message) publish.single(topic="/mqtt-dpsim", payload=m_message, hostname="mqtt") seq += 1 - time.sleep(T_s) \ No newline at end of file + time.sleep(T_s) diff --git a/examples/villas/dpsim-mqtt.py b/examples/villas/dpsim-mqtt.py index f50007efe2..0d31ba7625 100644 --- a/examples/villas/dpsim-mqtt.py +++ b/examples/villas/dpsim-mqtt.py @@ -1,5 +1,7 @@ # This example demonstrates the export of values calculated by dpsim to a MQTT broker using the VILLASnode interface -# Note, that dpsim also expects to read a (complex) reference voltage from MQTT, so the simulation will block on every timestep until this value is provided +# Note, that dpsim also expects to read a (complex) reference voltage from MQTT, so the simulation will block on every timestep until this value is provided + +import json import dpsimpy import dpsimpyvillas @@ -8,16 +10,16 @@ time_step = 0.01 final_time = 10 -n1 = dpsimpy.dp.SimNode('n1', dpsimpy.PhaseType.Single, [10]) -n2 = dpsimpy.dp.SimNode('n2', dpsimpy.PhaseType.Single, [5]) +n1 = dpsimpy.dp.SimNode("n1", dpsimpy.PhaseType.Single, [10]) +n2 = dpsimpy.dp.SimNode("n2", dpsimpy.PhaseType.Single, [5]) -evs = dpsimpy.dp.ph1.VoltageSource('v_intf', dpsimpy.LogLevel.debug) +evs = dpsimpy.dp.ph1.VoltageSource("v_intf", dpsimpy.LogLevel.debug) evs.set_parameters(complex(5, 0)) -vs1 = dpsimpy.dp.ph1.VoltageSource('vs_1', dpsimpy.LogLevel.debug) +vs1 = dpsimpy.dp.ph1.VoltageSource("vs_1", dpsimpy.LogLevel.debug) vs1.set_parameters(complex(10, 0)) -r12 = dpsimpy.dp.ph1.Resistor('r_12', dpsimpy.LogLevel.debug) +r12 = dpsimpy.dp.ph1.Resistor("r_12", dpsimpy.LogLevel.debug) r12.set_parameters(1) evs.connect([dpsimpy.dp.SimNode.gnd, n2]) @@ -26,38 +28,34 @@ sys = dpsimpy.SystemTopology(50, [n1, n2], [evs, vs1, r12]) -dpsimpy.Logger.set_log_dir('logs/' + sim_name) +dpsimpy.Logger.set_log_dir("logs/" + sim_name) logger = dpsimpy.Logger(sim_name) -logger.log_attribute('v1', 'v', n1) -logger.log_attribute('v2', 'v', n2) -logger.log_attribute('r12', 'i_intf', r12) -logger.log_attribute('ievs', 'i_intf', evs) -logger.log_attribute('vevs', 'v_intf', evs) +logger.log_attribute("v1", "v", n1) +logger.log_attribute("v2", "v", n2) +logger.log_attribute("r12", "i_intf", r12) +logger.log_attribute("ievs", "i_intf", evs) +logger.log_attribute("vevs", "v_intf", evs) sim = dpsimpy.RealTimeSimulation(sim_name) sim.set_system(sys) sim.set_time_step(time_step) sim.set_final_time(final_time) -mqtt_config = '''{ - "type": "mqtt", - "format": "json", - "host": "mqtt", - "in": { - "subscribe": "/mqtt-dpsim" - }, - "out": { - "publish": "/dpsim-mqtt" - } -}''' - -intf = dpsimpyvillas.InterfaceVillas(name='dpsim-mqtt', config=mqtt_config) -intf.import_attribute(evs.attr('V_ref'), 0, True) -intf.export_attribute(r12.attr('i_intf').derive_coeff(0, 0), 0) +intf_config = { + "type": "mqtt", + "format": "json", + "host": "mqtt", + "in": {"subscribe": "/mqtt-dpsim"}, + "out": {"publish": "/dpsim-mqtt"}, +} + +intf = dpsimpyvillas.InterfaceVillas(name="dpsim-mqtt", config=json.dumps(intf_config)) +intf.import_attribute(evs.attr("V_ref"), 0, True) +intf.export_attribute(r12.attr("i_intf").derive_coeff(0, 0), 0) sim.add_interface(intf) sim.add_logger(logger) -sim.run(1) \ No newline at end of file +sim.run(1) diff --git a/examples/villas/shmem-distributed-reference.py b/examples/villas/shmem-distributed-reference.py index f364a9619e..3bd953de95 100644 --- a/examples/villas/shmem-distributed-reference.py +++ b/examples/villas/shmem-distributed-reference.py @@ -10,18 +10,18 @@ import villas.dataprocessing.readtools as rt import villas.dataprocessing.plottools as pt -if __name__ == '__main__': +if __name__ == "__main__": sim_name = "ShmemDistributed" time_step = 0.001 - n1 = dpsimpy.dp.SimNode('n1') - n2 = dpsimpy.dp.SimNode('n2') + n1 = dpsimpy.dp.SimNode("n1") + n2 = dpsimpy.dp.SimNode("n2") - vs1 = dpsimpy.dp.ph1.VoltageSource('vs_1', dpsimpy.LogLevel.debug) + vs1 = dpsimpy.dp.ph1.VoltageSource("vs_1", dpsimpy.LogLevel.debug) vs1.set_parameters(complex(10, 0)) - r12 = dpsimpy.dp.ph1.Resistor('r_1', dpsimpy.LogLevel.debug) + r12 = dpsimpy.dp.ph1.Resistor("r_1", dpsimpy.LogLevel.debug) r12.set_parameters(1) - r02 = dpsimpy.dp.ph1.Resistor('r_02', dpsimpy.LogLevel.debug) + r02 = dpsimpy.dp.ph1.Resistor("r_02", dpsimpy.LogLevel.debug) r02.set_parameters(1) vs1.connect([dpsimpy.dp.SimNode.gnd, n1]) @@ -30,13 +30,13 @@ sys = dpsimpy.SystemTopology(50, [n1, n2], [vs1, r12, r02]) - dpsimpy.Logger.set_log_dir('logs/' + sim_name) + dpsimpy.Logger.set_log_dir("logs/" + sim_name) logger = dpsimpy.Logger(sim_name) - logger.log_attribute('v1', 'v', n1) - logger.log_attribute('v2', 'v', n2) - logger.log_attribute('r12', 'i_intf', r12) - logger.log_attribute('r02', 'i_intf', r02) + logger.log_attribute("v1", "v", n1) + logger.log_attribute("v2", "v", n2) + logger.log_attribute("r12", "i_intf", r12) + logger.log_attribute("r02", "i_intf", r02) sim = dpsimpy.RealTimeSimulation(sim_name) sim.set_system(sys) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..65cfa8ea78 --- /dev/null +++ b/flake.lock @@ -0,0 +1,96 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1742800061, + "narHash": "sha256-oDJGK1UMArK52vcW9S5S2apeec4rbfNELgc50LqiPNs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1750f3c1c89488e2ffdd47cab9d05454dddfb734", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1759070547, + "narHash": "sha256-JVZl8NaVRYb0+381nl7LvPE+A774/dRpif01FKLrYFQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "647e5c14cbd5067f44ac86b74f014962df460840", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "villas-node": "villas-node" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "villas-node": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1759121869, + "narHash": "sha256-RQJ02SVEq5l+MGe3++SIgrzZDJm/zHRwIGMnMoUBpUU=", + "owner": "VILLASframework", + "repo": "node", + "rev": "5606793aaee2d1eeb663180d3e52718fa8bd5931", + "type": "github" + }, + "original": { + "owner": "VILLASframework", + "repo": "node", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000..2c6ee9c104 --- /dev/null +++ b/flake.nix @@ -0,0 +1,57 @@ +{ + description = "DPsim - Solver library for dynamic power system simulation"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + villas-node = { + url = "github:VILLASframework/node"; + }; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + villas-node, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { + inherit system; + + # Required for old sundials version + config.permittedInsecurePackages = [ "python-2.7.18.8" ]; + overlays = [ + (final: prev: let + villasPkg = villas-node.packages.${system}.villas-node; + in { + readerwriterqueue = final.callPackage ./packaging/Nix/readerwriterqueue.nix { }; + cimpp = final.callPackage ./packaging/Nix/cimpp.nix { }; + suitesparse-dpsim = prev.callPackage ./packaging/Nix/suitesparse.nix { }; + sundials321 = prev.callPackage ./packaging/Nix/sundials.nix { }; + dpsim = final.callPackage ./packaging/Nix/dpsim.nix { villas-node=villasPkg; }; + dpsimpy = final.callPackage ./packaging/Nix/dpsimpy.nix { }; + }) + ]; + }; + in { + packages = { + default = pkgs.dpsim; + + inherit (pkgs) + dpsim + dpsimpy + readerwriterqueue + cimpp + ; + }; + + devShells = { + default = pkgs.callPackage ./packaging/Nix/shell.nix { }; + }; + } + ); +} diff --git a/packaging/Docker/Dockerfile b/packaging/Docker/Dockerfile index 2a28ad662c..263f96cd64 100644 --- a/packaging/Docker/Dockerfile +++ b/packaging/Docker/Dockerfile @@ -4,10 +4,10 @@ ARG BASE_IMAGE=sogno/dpsim:dev FROM ${BASE_IMAGE} LABEL \ - org.opencontainers.image.title = "DPsim" \ - org.opencontainers.image.licenses = "MPL 2.0" \ - org.opencontainers.image.url = "http://dpsim.fein-aachen.org/" \ - org.opencontainers.image.source = "https://github.com/sogno-platform/dpsim" + org.opencontainers.image.title="DPsim" \ + org.opencontainers.image.licenses="MPL 2.0" \ + org.opencontainers.image.url="http://dpsim.fein-aachen.org/" \ + org.opencontainers.image.source="https://github.com/sogno-platform/dpsim" COPY . /dpsim/ RUN rm -rf /dpsim/build && mkdir /dpsim/build diff --git a/packaging/Docker/Dockerfile.dev b/packaging/Docker/Dockerfile.dev index c12d260950..8cb173b290 100644 --- a/packaging/Docker/Dockerfile.dev +++ b/packaging/Docker/Dockerfile.dev @@ -1,8 +1,9 @@ -FROM fedora:36 AS base +FROM fedora:42 AS base ARG CIM_VERSION=CGMES_2.4.15_16FEB2016 -ARG CIMPP_COMMIT=1b11d5c17bedf0ae042628b42ecb4e49df70b2f6 -ARG VILLAS_VERSION=18cdd2a6364d05fbf413ca699616cd324abfcb54 +ARG LIBCIMPP_VERSION=2.2.0 +ARG CIMPP_COMMIT=051ee4c311572fe92b30120b897d22deb253e162 +ARG VILLAS_VERSION=5606793aaee2d1eeb663180d3e52718fa8bd5931 ARG CMAKE_OPTS ARG MAKE_OPTS=-j4 @@ -13,35 +14,42 @@ LABEL \ org.opencontainers.image.url="http://dpsim.fein-aachen.org/" \ org.opencontainers.image.source="https://github.com/sogno-platform/dpsim" -RUN dnf -y update - -# Toolchain -RUN dnf -y install \ - gcc gcc-c++ clang \ - git \ - rpmdevtools rpm-build \ - make cmake pkgconfig \ - python3-pip \ - cppcheck - -# Tools needed for developement -RUN dnf -y install \ - doxygen graphviz \ - gdb \ - procps-ng - -# Dependencies -RUN dnf --refresh -y install \ - python3-devel \ - eigen3-devel \ - libxml2-devel \ - graphviz-devel \ - spdlog-devel \ - fmt-devel - -# Install some debuginfos -RUN dnf -y debuginfo-install \ - python3 +RUN set -eux; \ + dnf -y update; \ + dnf -y remove systemd-standalone-tmpfiles || true; \ + dnf -y --refresh install \ + gcc gcc-c++ clang \ + git \ + rpmdevtools rpm-build \ + make cmake pkgconfig \ + python3-pip \ + curl \ + cppcheck \ + flex bison \ + protobuf-compiler protobuf-c-compiler \ + clang-tools-extra \ + doxygen graphviz \ + gdb \ + procps-ng \ + python3-devel \ + eigen3-devel \ + libxml2-devel \ + graphviz-devel \ + spdlog-devel \ + fmt-devel \ + openssl-devel \ + libuuid-devel \ + libcurl-devel \ + jansson-devel \ + libwebsockets-devel \ + mosquitto-devel \ + libconfig-devel \ + libnl3-devel \ + protobuf-devel \ + protobuf-c-devel \ + libre-devel; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum # Build & Install sundials RUN cd /tmp && \ @@ -54,63 +62,53 @@ RUN cd /tmp && \ # CIMpp and VILLASnode are installed here ENV LD_LIBRARY_PATH="/usr/local/lib64:${LD_LIBRARY_PATH}" -# Install minimal VILLASnode dependencies -RUN dnf -y install \ - openssl-devel \ - libuuid-devel \ - libcurl-devel \ - jansson-devel \ - libwebsockets-devel - -# Install optional VILLASnode dependencies -RUN dnf -y install \ - mosquitto-devel \ - libconfig-devel \ - libnl3-devel \ - protobuf-devel \ - protobuf-c-devel - # Python dependencies -ADD requirements.txt . -RUN pip3 install --upgrade wheel build -RUN pip3 install -r requirements.txt - -# Install CIMpp from source -RUN cd /tmp && \ - git clone https://github.com/sogno-platform/libcimpp.git && \ - mkdir -p libcimpp/build && cd libcimpp/build && \ - git checkout ${CIMPP_COMMIT} && \ - git submodule update --init && \ - cmake ${CMAKE_OPTS} ..\ - -DBUILD_SHARED_LIBS=ON \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 \ - -DUSE_CIM_VERSION=${CIM_VERSION} \ - -DBUILD_ARABICA_EXAMPLES=OFF && \ - make ${MAKE_OPTS} install && \ - rm -rf /tmp/libcimpp - -# Install VILLASnode from source +COPY requirements.txt . +RUN pip3 install --no-cache-dir --upgrade wheel build setuptools packaging && \ + pip3 install --no-cache-dir -r requirements.txt && \ + pip3 cache purge + +# Install libcimpp from prebuilt RPMs +RUN set -eux; \ + case "${CIM_VERSION}" in \ + CGMES_2.4.15_16FEB2016|CGMES_2.4.15_27JAN2020|CGMES_2.4.13_18DEC2013) \ + libcimpp_pkg="libcimpp_${CIM_VERSION}-${LIBCIMPP_VERSION}-Linux.rpm" ;; \ + *) \ + echo "Unsupported CIM_VERSION '${CIM_VERSION}' for prebuilt libcimpp package" >&2; \ + exit 1 ;; \ + esac; \ + libcimpp_url="https://github.com/sogno-platform/libcimpp/releases/download/release%2Fv${LIBCIMPP_VERSION}/${libcimpp_pkg}"; \ + curl -sSL "${libcimpp_url}" -o /tmp/libcimpp.rpm; \ + dnf -y install /tmp/libcimpp.rpm; \ + rm -f /tmp/libcimpp.rpm; \ + ldconfig; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum + +# Install VILLASnode from source (with fpga support) RUN cd /tmp && \ git clone --recurse-submodules https://github.com/VILLASframework/node.git villas-node && \ mkdir -p villas-node/build && cd villas-node/build && \ git checkout ${VILLAS_VERSION} && \ cmake ${CMAKE_OPTS} .. \ -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 \ - -DDOWNLOAD_GO=OFF && \ + -DCMAKE_BUILD_TYPE=Release && \ make ${MAKE_OPTS} install && \ rm -rf /tmp/villas-node # Remove this part in the future and use dedicated Jupyter Dockerfile -# Activate Jupyter extensions -RUN dnf -y --refresh install \ - npm - -RUN pip3 install \ - jupyter \ - jupyterlab \ - jupyter_contrib_nbextensions \ - nbconvert \ - nbformat +RUN set -eux; \ + dnf -y --refresh install npm; \ + pip3 install --no-cache-dir \ + jupyter \ + jupyterlab \ + jupyter_contrib_nbextensions \ + nbconvert \ + nbformat; \ + pip3 cache purge; \ + dnf -y remove npm; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum EXPOSE 8888 diff --git a/packaging/Docker/Dockerfile.dev-debian b/packaging/Docker/Dockerfile.dev-debian index f49bc69746..bb4a0fd615 100644 --- a/packaging/Docker/Dockerfile.dev-debian +++ b/packaging/Docker/Dockerfile.dev-debian @@ -1,44 +1,48 @@ FROM debian:11 ARG CIM_VERSION=CGMES_2.4.15_16FEB2016 -ARG CIMPP_COMMIT=1b11d5c17bedf0ae042628b42ecb4e49df70b2f6 -ARG VILLAS_VERSION=18cdd2a6364d05fbf413ca699616cd324abfcb54 +ARG LIBCIMPP_VERSION=2.2.0 +ARG VILLAS_VERSION=5606793aaee2d1eeb663180d3e52718fa8bd5931 ARG CMAKE_OPTS ARG MAKE_OPTS=-j4 LABEL \ - org.opencontainers.image.title = "DPsim" \ - org.opencontainers.image.licenses = "MPL 2.0" \ - org.opencontainers.image.url = "http://dpsim.fein-aachen.org/" \ - org.opencontainers.image.source = "https://github.com/sogno-platform/dpsim" - -RUN apt-get -y update - -# Toolchain -RUN apt-get -y install \ - gcc g++ clang \ - git \ - make cmake pkg-config \ - python3-pip \ - wget - -# Tools needed for developement -RUN apt-get -y install \ - doxygen graphviz \ - gdb - -# Dependencies -RUN apt-get -y install \ - python3-dev \ - libeigen3-dev \ - libxml2-dev \ - libgraphviz-dev \ - libgsl-dev \ - libspdlog-dev \ - pybind11-dev \ - libspdlog-dev \ - libfmt-dev + org.opencontainers.image.title="DPsim" \ + org.opencontainers.image.licenses="MPL 2.0" \ + org.opencontainers.image.url="http://dpsim.fein-aachen.org/" \ + org.opencontainers.image.source="https://github.com/sogno-platform/dpsim" + +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + gcc g++ clang \ + git \ + make cmake pkg-config \ + python3-pip \ + wget \ + doxygen graphviz \ + gdb \ + python3-dev \ + libeigen3-dev \ + libxml2-dev \ + libgraphviz-dev \ + libgsl-dev \ + libspdlog-dev \ + pybind11-dev \ + libfmt-dev \ + libssl-dev \ + uuid-dev \ + libcurl4-gnutls-dev \ + libjansson-dev \ + libwebsockets-dev \ + libmosquitto-dev \ + libconfig-dev \ + libnl-3-dev \ + protobuf-dev \ + libprotobuf-c-dev; \ + apt-get clean; \ + rm -rf /var/lib/apt/lists/* # Build & Install sundials RUN cd /tmp && \ @@ -46,23 +50,8 @@ RUN cd /tmp && \ mkdir -p sundials/build && cd sundials/build && \ cmake ${CMAKE_OPTS} .. \ -DCMAKE_BUILD_TYPE=Release && \ - make ${MAKE_OPTS} install - -## Install minimal VILLASnode dependencies -RUN apt-get -y install \ - libssl-dev \ - uuid-dev \ - libcurl4-gnutls-dev \ - libjansson-dev \ - libwebsockets-dev - -## Install optional VILLASnode dependencies -RUN apt-get -y install \ - libmosquitto-dev \ - libconfig-dev \ - libnl-3-dev \ - protobuf-dev \ - libprotobuf-c-dev + make ${MAKE_OPTS} install && \ + rm -rf /tmp/sundials ## Install libiec61850 from source RUN cd /tmp && \ @@ -76,22 +65,28 @@ RUN cd /tmp && \ rm -rf /tmp/libiec61850-1.3.3 ## Python dependencies -ADD requirements.txt . -RUN pip3 install -r requirements.txt - -## Install CIMpp from source -RUN cd /tmp && \ - git clone https://github.com/sogno-platform/libcimpp.git && \ - mkdir -p libcimpp/build && cd libcimpp/build && \ - git checkout ${CIMPP_COMMIT} && \ - git submodule update --init && \ - cmake ${CMAKE_OPTS} .. \ - -DBUILD_SHARED_LIBS=ON \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib \ - -DUSE_CIM_VERSION=${CIM_VERSION} \ - -DBUILD_ARABICA_EXAMPLES=OFF && \ - make ${MAKE_OPTS} install && \ - rm -rf /tmp/libcimpp +COPY requirements.txt . +RUN pip3 install --no-cache-dir --upgrade wheel build setuptools packaging && \ + pip3 install --no-cache-dir -r requirements.txt && \ + pip3 cache purge + +## Install libcimpp from prebuilt Debian packages +RUN set -eux; \ + case "${CIM_VERSION}" in \ + CGMES_2.4.15_16FEB2016|CGMES_2.4.15_27JAN2020|CGMES_2.4.13_18DEC2013) \ + libcimpp_pkg="libcimpp_${CIM_VERSION}-${LIBCIMPP_VERSION}-Linux.deb" ;; \ + *) \ + echo "Unsupported CIM_VERSION '${CIM_VERSION}' for prebuilt libcimpp package" >&2; \ + exit 1 ;; \ + esac; \ + libcimpp_url="https://github.com/sogno-platform/libcimpp/releases/download/release%2Fv${LIBCIMPP_VERSION}/${libcimpp_pkg}"; \ + wget -qO /tmp/libcimpp.deb "${libcimpp_url}"; \ + apt-get update; \ + apt-get install -y --no-install-recommends /tmp/libcimpp.deb; \ + rm -f /tmp/libcimpp.deb; \ + ldconfig; \ + apt-get clean; \ + rm -rf /var/lib/apt/lists/* ## Install VILLASnode from source RUN cd /tmp && \ @@ -101,19 +96,28 @@ RUN cd /tmp && \ cmake ${CMAKE_OPTS} .. \ -DCMAKE_INSTALL_LIBDIR=/usr/local/lib \ -DDOWNLOAD_GO=OFF && \ - make install && \ + make ${MAKE_OPTS} install && \ rm -rf /tmp/villas-node # Remove this part in the future and use dedicated Jupyter Dockerfile # Activate Jupyter extensions -RUN apt-get -y install \ - npm +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends npm; \ + rm -rf /var/lib/apt/lists/* -RUN pip3 install \ +RUN pip3 install --no-cache-dir \ jupyter \ jupyterlab \ jupyter_contrib_nbextensions \ nbconvert \ - nbformat + nbformat && \ + pip3 cache purge + +RUN set -eux; \ + apt-get purge -y npm && \ + apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* EXPOSE 8888 diff --git a/packaging/Docker/Dockerfile.dev-docs b/packaging/Docker/Dockerfile.dev-docs index a5286fcb4a..6a322252ba 100644 --- a/packaging/Docker/Dockerfile.dev-docs +++ b/packaging/Docker/Dockerfile.dev-docs @@ -3,7 +3,7 @@ FROM ubuntu:latest RUN apt update RUN apt install -y git golang curl sudo RUN curl -fsSL https://deb.nodesource.com/setup_19.x | sudo -E bash - && \ - sudo apt-get install -y nodejs + sudo apt-get install -y nodejs RUN go install -tags extended github.com/gohugoio/hugo@latest RUN cp /root/go/bin/hugo /usr/bin/hugo EXPOSE 1313/tcp diff --git a/packaging/Docker/Dockerfile.dev-minimal b/packaging/Docker/Dockerfile.dev-minimal index 1394c8efc6..27c52490e7 100644 --- a/packaging/Docker/Dockerfile.dev-minimal +++ b/packaging/Docker/Dockerfile.dev-minimal @@ -1,29 +1,29 @@ -FROM fedora:36 +FROM fedora:42 LABEL \ - org.opencontainers.image.title = "DPsim" \ - org.opencontainers.image.licenses = "MPL 2.0" \ - org.opencontainers.image.url = "http://dpsim.fein-aachen.org/" \ - org.opencontainers.image.source = "https://github.com/sogno-platform/dpsim" + org.opencontainers.image.title="DPsim" \ + org.opencontainers.image.licenses="MPL 2.0" \ + org.opencontainers.image.url="http://dpsim.fein-aachen.org/" \ + org.opencontainers.image.source="https://github.com/sogno-platform/dpsim" -RUN dnf -y update - -# Toolchain -RUN dnf -y install \ - gcc gcc-c++ \ - git \ - make cmake pkgconfig \ - python3-pip - -# Dependencies -RUN dnf --refresh -y install \ - python3-devel \ - eigen3-devel \ - spdlog-devel +RUN set -eux; \ + dnf -y update; \ + dnf -y remove systemd-standalone-tmpfiles || true; \ + dnf -y --refresh install \ + gcc gcc-c++ \ + git \ + make cmake pkgconfig \ + python3-pip \ + python3-devel \ + eigen3-devel \ + spdlog-devel; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum # Python dependencies -ADD requirements.txt . -RUN pip3 install --upgrade wheel build -RUN pip3 install -r requirements.txt +COPY requirements.txt . +RUN pip3 install --no-cache-dir --upgrade wheel build setuptools packaging && \ + pip3 install --no-cache-dir -r requirements.txt && \ + pip3 cache purge EXPOSE 8888 diff --git a/packaging/Docker/Dockerfile.dev-rocky b/packaging/Docker/Dockerfile.dev-rocky index 236d6b9d84..d32aab94a2 100644 --- a/packaging/Docker/Dockerfile.dev-rocky +++ b/packaging/Docker/Dockerfile.dev-rocky @@ -1,7 +1,8 @@ FROM rockylinux:9 ARG CIM_VERSION=CGMES_2.4.15_16FEB2016 -ARG CIMPP_COMMIT=1b11d5c17bedf0ae042628b42ecb4e49df70b2f6 +ARG CIMPP_COMMIT=051ee4c311572fe92b30120b897d22deb253e162 +ARG VILLAS_VERSION=5606793aaee2d1eeb663180d3e52718fa8bd5931 ARG CMAKE_OPTS ARG MAKE_OPTS=-j4 @@ -40,7 +41,9 @@ RUN dnf -y install \ wget \ libarchive \ openblas-devel \ - gcc-gfortran + gcc-gfortran \ + coreutils-single \ + glib2-devel # Dependencies RUN dnf --refresh -y install \ @@ -61,7 +64,16 @@ RUN dnf -y install \ jansson-devel \ mosquitto-devel \ libjpeg-devel \ - zlib-devel + zlib-devel \ + protobuf-c-devel \ + protobuf-devel \ + libmodbus-devel \ + librdkafka-devel \ + zeromq-devel \ + libusb-devel \ + lua-devel \ + nanomsg-devel \ + git-svn # CUDARPC and dependencies RUN dnf install -y \ @@ -90,6 +102,14 @@ RUN dnf -y install \ qt5-qtbase qt5-qtsvg RUN pip3 install gprof2dot +# Build & Install sundials +RUN cd /tmp && \ + git clone --branch v3.2.1 --recurse-submodules --depth 1 https://github.com/LLNL/sundials.git && \ + mkdir -p sundials/build && cd sundials/build && \ + cmake ${CMAKE_OPTS} .. \ + -DCMAKE_BUILD_TYPE=Release && \ + make ${MAKE_OPTS} install + # Install CIMpp from source RUN cd /tmp && \ git clone https://github.com/sogno-platform/libcimpp.git && \ @@ -116,18 +136,34 @@ RUN cd /tmp && \ -DBUILD_SHARED_LIBS=on && \ make ${MAKE_OPTS} install && rm -rf /tmp/magma-2.6.0 +# Install VILLASnode and deps from source +ENV CMAKE_OPTS="${CMAKE_OPTS} \ + -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \ + -DCMAKE_CUDA_ARCHITECTURES=60;61;70;75" + +RUN cd /tmp && \ + git clone --recurse-submodules https://github.com/VILLASframework/node.git villas-node && \ + cd villas-node && \ + git checkout ${VILLAS_VERSION} && \ + # libxil is currently not working in the VILLASnode installer script, skip and use submodule for FPGA support + env MAKE_OPTS="" DEPS_NONINTERACTIVE=1 DEPS_SKIP=libxil bash packaging/deps.sh && \ + mkdir -p build && cd build && \ + cmake ${CMAKE_OPTS} .. \ + -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS -fpermissive" \ + -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 \ + -DCMAKE_CUDA_FLAGS="-Xcompiler=-Wall,-Werror" && \ + make ${MAKE_OPTS} install && \ + rm -rf /tmp/villas-node + # CIMpp and VILLASnode are installed here ENV LD_LIBRARY_PATH="/usr/local/lib64:${LD_LIBRARY_PATH}" -# # Python dependencies -# ADD requirements.txt . -# RUN pip3 install -U setuptools -# RUN pip3 install -U wheel -# RUN pip3 install -r requirements.txt +# This is a hack: the VILLASnode build system does not install the libraries in the correct location for OpenDSS +RUN echo "/usr/local/openDSSC/bin" > /etc/ld.so.conf.d/opendssc.conf && \ + ldconfig -# # Remove this part in the future and use dedicated Jupyter Dockerfile -# # Activate Jupyter extensions -# RUN dnf -y --refresh install npm -# RUN pip3 install jupyter jupyter_contrib_nbextensions nbconvert nbformat +# Python dependencies +COPY requirements.txt requirements.txt +RUN pip3 install --upgrade wheel build setuptools packaging && pip3 install -r requirements.txt EXPOSE 8888 diff --git a/packaging/Docker/Dockerfile.manylinux b/packaging/Docker/Dockerfile.manylinux index a27a4e53b8..b01fdbed52 100644 --- a/packaging/Docker/Dockerfile.manylinux +++ b/packaging/Docker/Dockerfile.manylinux @@ -6,8 +6,8 @@ FROM quay.io/pypa/manylinux_2_28_x86_64 ARG CIM_VERSION=CGMES_2.4.15_16FEB2016 -ARG CIMPP_COMMIT=1b11d5c17bedf0ae042628b42ecb4e49df70b2f6 -ARG VILLAS_VERSION=18cdd2a6364d05fbf413ca699616cd324abfcb54 +ARG CIMPP_COMMIT=051ee4c311572fe92b30120b897d22deb253e162 +ARG VILLAS_VERSION=5606793aaee2d1eeb663180d3e52718fa8bd5931 ARG CMAKE_OPTS ARG MAKE_OPTS=-j4 @@ -21,18 +21,21 @@ LABEL \ org.opencontainers.image.source="https://github.com/sogno-platform/dpsim" RUN dnf -y update -RUN yum install -y epel-release +RUN dnf install -y epel-release # Toolchain -RUN yum install -y \ - gcc-toolset-11 clang \ - git \ +RUN dnf install -y \ + gcc-toolset-14 \ + git wget \ rpmdevtools rpm-build \ - make cmake pkgconfig \ + make cmake pkgconfig libtool \ + autoconf automake autogen libtool flex bison \ python3-pip \ - cppcheck + cppcheck \ + ninja-build \ + meson -# Tools needed for developement +# Tools needed for development RUN dnf -y install \ doxygen graphviz \ gdb \ @@ -45,8 +48,6 @@ RUN dnf --refresh -y install \ libxml2-devel \ graphviz-devel -RUN yum install -y fmt-devel - # Install some debuginfos RUN dnf -y debuginfo-install \ python3 @@ -56,15 +57,14 @@ RUN cd /tmp && \ git clone --branch v3.2.1 --recurse-submodules https://github.com/LLNL/sundials.git && \ mkdir -p sundials/build && cd sundials/build && \ cmake ${CMAKE_OPTS} .. \ - -DCMAKE_BUILD_TYPE=Release && \ + -DBUILD_SHARED_LIBS=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 && \ make ${MAKE_OPTS} install -# CIMpp and VILLASnode are installed here -ENV LD_LIBRARY_PATH="/usr/local/lib64:${LD_LIBRARY_PATH}" - # Python dependencies ADD requirements-manylinux.txt . -RUN pip3 install --upgrade wheel build +RUN pip3 install --upgrade wheel build setuptools packaging RUN pip3 install -r requirements-manylinux.txt # Install CIMpp from source @@ -74,7 +74,6 @@ RUN cd /tmp && \ git checkout ${CIMPP_COMMIT} && \ git submodule update --init && \ cmake ${CMAKE_OPTS} .. \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 \ -DUSE_CIM_VERSION=${CIM_VERSION} \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_ARABICA_EXAMPLES=OFF && \ @@ -82,39 +81,49 @@ RUN cd /tmp && \ rm -rf /tmp/libcimpp # Install VILLASnode dependencies -RUN yum install -y \ - openssl-devel \ - libuuid-devel \ - libcurl-devel \ +RUN dnf install -y \ jansson-devel \ - libwebsockets-devel \ - mosquitto-devel \ libconfig-devel \ + libcurl-devel \ + libibverbs-devel \ + libmodbus-devel \ + libnice-devel \ libnl3-devel \ + librdkafka-devel \ + librdmacm-devel \ + libusb-devel \ + libuuid-devel \ + lua-devel \ + mosquitto-devel \ + openssl-devel \ + protobuf-c-devel \ protobuf-devel \ - protobuf-c-devel - -# Install spdlog from source -RUN cd /tmp && \ - git clone --branch v1.6.1 --recurse-submodules --depth 1 https://github.com/gabime/spdlog.git && \ - mkdir -p spdlog/build && cd spdlog/build && \ - cmake ${CMAKE_OPTS} .. \ - -DCMAKE_POSITION_INDEPENDENT_CODE=True \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 && \ - make ${MAKE_OPTS} install && \ - rm -rf /tmp/spdlog + nanomsg-devel \ + zeromq-devel \ + graphviz-devel \ + git-svn \ + subversion \ + subversion-perl \ + perl-Memoize # Install VILLASnode from source RUN cd /tmp && \ git clone --recurse-submodules https://github.com/VILLASframework/node.git villas-node && \ - mkdir -p villas-node/build && cd villas-node/build && \ + cd villas-node && \ git checkout ${VILLAS_VERSION} && \ + DEPS_SKIP=criterion,ethercat \ + MAKE_OPTS="" \ + CMAKE_OPTS=-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + NINJA=/usr/bin/ninja-build \ + bash packaging/deps.sh && \ + mkdir -p build && cd build && \ cmake ${CMAKE_OPTS} .. \ - -DCMAKE_C_COMPILER:FILEPATH=/opt/rh/gcc-toolset-11/root/usr/bin/gcc \ - -DCMAKE_CXX_COMPILER:FILEPATH=/opt/rh/gcc-toolset-11/root/usr/bin/g++ \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 \ - -DDOWNLOAD_GO=OFF && \ + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 && \ make ${MAKE_OPTS} install && \ rm -rf /tmp/villas-node -ENV CMAKE_OPTS="-DCMAKE_C_COMPILER:FILEPATH=/opt/rh/gcc-toolset-11/root/usr/bin/gcc -DCMAKE_CXX_COMPILER:FILEPATH=/opt/rh/gcc-toolset-11/root/usr/bin/g++" + # Fix OpenDSSC library path + RUN if [ -f /usr/local/openDSSC/bin/libOpenDSSC.so ]; then \ + mkdir -p /usr/lib64; \ + ln -sf /usr/local/openDSSC/bin/libOpenDSSC.so /usr/lib64/libOpenDSSC.so; \ + fi diff --git a/packaging/Docker/Dockerfile.rpm b/packaging/Docker/Dockerfile.rpm index 84b8ab6a8a..7647dd7937 100644 --- a/packaging/Docker/Dockerfile.rpm +++ b/packaging/Docker/Dockerfile.rpm @@ -16,27 +16,44 @@ RUN cmake ${CMAKE_OPTS} .. \ -DCPACK_GENERATOR=RPM RUN make ${MAKE_OPTS} package -FROM fedora:36 +FROM fedora:42 LABEL \ - org.opencontainers.image.title = "DPsim" \ - org.opencontainers.image.licenses = "MPL 2.0" \ - org.opencontainers.image.url = "http://dpsim.fein-aachen.org/" \ - org.opencontainers.image.source = "https://github.com/sogno-platform/dpsim" + org.opencontainers.image.title="DPsim" \ + org.opencontainers.image.licenses="MPL 2.0" \ + org.opencontainers.image.url="http://dpsim.fein-aachen.org/" \ + org.opencontainers.image.source="https://github.com/sogno-platform/dpsim" + +RUN set -eux; \ + dnf -y update; \ + dnf -y remove systemd-standalone-tmpfiles || true; \ + dnf -y --refresh install \ + python3-pip \ + findutils; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum COPY --from=builder /dpsim/build/*.rpm /tmp -RUN dnf -y install /tmp/*.rpm - -ADD requirements.txt . -RUN pip3 install -r requirements.txt - -# Remove this part in the future and use dedicated Jupyter Dockerfile -# Activate Jupyter extensions -ADD requirements-jupyter.txt . -RUN pip3 install -r requirements-jupyter.txt -RUN dnf -y --refresh install npm -RUN jupyter nbextension enable --py widgetsnbextension -RUN jupyter labextension install @jupyter-widgets/jupyterlab-manager +RUN set -eux; \ + dnf -y install /tmp/*.rpm; \ + rm -f /tmp/*.rpm; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum + +COPY requirements.txt . +COPY requirements-jupyter.txt . +RUN pip3 install --no-cache-dir --upgrade wheel build setuptools packaging && \ + pip3 install --no-cache-dir -r requirements.txt && \ + pip3 install --no-cache-dir -r requirements-jupyter.txt && \ + pip3 cache purge + +RUN set -eux; \ + dnf -y --refresh install npm; \ + jupyter nbextension enable --py widgetsnbextension; \ + jupyter labextension install @jupyter-widgets/jupyterlab-manager; \ + dnf -y remove npm; \ + dnf clean all; \ + rm -rf /var/cache/dnf /var/cache/yum # Copy example materials RUN mkdir dpsim diff --git a/packaging/Nix/cimpp.nix b/packaging/Nix/cimpp.nix new file mode 100644 index 0000000000..0f56657e89 --- /dev/null +++ b/packaging/Nix/cimpp.nix @@ -0,0 +1,47 @@ +{ + fetchFromGitHub, + stdenv, + lib, + cmake, + libxml2, + fetchurl, + + # Options + cimVersion ? "CGMES_2.4.15_16FEB2016", +}: +let + libxml2_2914 = + (libxml2.overrideAttrs ( + finalAttrs: prevAttrs: { + version = "2.9.14"; + src = fetchurl { + url = "mirror://gnome/sources/libxml2/${lib.versions.majorMinor finalAttrs.version}/libxml2-${finalAttrs.version}.tar.xz"; + hash = "sha256-YNdKJX0czsBHXnScui8hVZ5IE577pv8oIkNXx8eY3+4"; + }; + patches = [ ]; + } + )).override + { pythonSupport = false; }; +in +stdenv.mkDerivation { + name = "libcimpp"; + src = fetchFromGitHub { + owner = "sogno-platform"; + repo = "libcimpp"; + # rev = "release/v2.2.0"; + rev = "051ee4c311572fe92b30120b897d22deb253e162"; + hash = "sha256-jyeiySIOPceH1/ZHRYsp1LczTlXuIapkMtCqlq2lZM0="; + fetchSubmodules = true; + }; + + nativeBuildInputs = [ cmake ]; + + cmakeFlags = [ + "-DUSE_CIM_VERSION=${cimVersion}" + "-DBUILD_SHARED_LIBS=ON" + ]; + + enableParallelBuilding = true; + + buildInputs = [ libxml2_2914 ]; +} diff --git a/packaging/Nix/dpsim.nix b/packaging/Nix/dpsim.nix new file mode 100644 index 0000000000..5acd981ac9 --- /dev/null +++ b/packaging/Nix/dpsim.nix @@ -0,0 +1,118 @@ +{ + lib, + stdenv, + + makeFontsConf, + + cimpp, + cmake, + doxygen, + eigen, + fmt, + graphviz, + gsl, + nlohmann_json, + pkg-config, + python312, + python312Packages, + readerwriterqueue, + spdlog, + sphinx, + sundials321, + suitesparse-dpsim, + villas-node, + freefont_ttf, + + cudatoolkit, + magma, + + # Options + withExamples ? false, + withAllExtras ? true, + withOpenMP ? withAllExtras, + withCIMpp ? withAllExtras, + withDocumentation ? withAllExtras, + withVILLAS ? withAllExtras, + withGSL ? withAllExtras, + withGraphviz ? withAllExtras, + withPybind ? withAllExtras, + withSundials ? withAllExtras, + withSuiteSparse ? withAllExtras, + withMNASolverPlugin ? withAllExtras, +}: +stdenv.mkDerivation { + name = "dpsim"; + src = ../..; + + nativeBuildInputs = + [ + cmake + pkg-config + ] + ++ lib.optionals withDocumentation [ + doxygen + sphinx + python312Packages.sphinx-rtd-theme + ]; + + buildInputs = + [ + eigen + fmt + spdlog + nlohmann_json + readerwriterqueue + + # TODO: Add these dependencies + # cudatoolkit + # magma + ] + ++ lib.optional withCIMpp cimpp + ++ lib.optional withVILLAS villas-node + ++ lib.optional withGSL gsl + ++ lib.optional withGraphviz graphviz + ++ lib.optional withSundials sundials321 + ++ lib.optional withSuiteSparse suitesparse-dpsim + ++ lib.optionals withPybind [ + python312 + python312Packages.pybind11 + ]; + + enableParallelBuilding = true; + + cmakeFlags = [ + # LTO is currently broken in Nixpkgs (https://github.com/NixOS/nixpkgs/issues/384599) + "-DWITH_LTO=OFF" + + "-DBUILD_SHARED_LIBS=ON" + + # Feature flags + "-DWITH_OPENMP=${if withOpenMP then "ON" else "OFF"}" + "-DWITH_CIM=${if withCIMpp then "ON" else "OFF"}" + "-DWITH_VILLAS=${if withVILLAS then "ON" else "OFF"}" + "-DWITH_GSL=${if withGSL then "ON" else "OFF"}" + "-DWITH_MNASOLVER_PLUGIN=${if withMNASolverPlugin then "ON" else "OFF"}" + + "-DDPSIM_BUILD_EXAMPLES=${if withExamples then "ON" else "OFF"}" + "-DDPSIM_BUILD_DOC=${if withDocumentation then "ON" else "OFF"}" + + # We can not fetch external code within the Nix sandbox + # Instead we packaged those dependencies as separate Nix derivations. + "-DFETCH_EIGEN=OFF" + "-DFETCH_SUITESPARSE=OFF" + "-DFETCH_SPDLOG=OFF" + "-DFETCH_CIMPP=OFF" + "-DFETCH_PYBIND=OFF" + "-DFETCH_GRID_DATA=OFF" + "-DFETCH_FILESYSTEM=OFF" + "-DFETCH_JSON=OFF" + "-DFETCH_READERWRITERQUEUE=OFF" + ]; + + FONTCONFIG_FILE = makeFontsConf { fontDirectories = [ freefont_ttf ]; }; + + # For building docs diagrams + preBuild = '' + export XDG_CACHE_HOME="$(mktemp -d)" + ''; +} diff --git a/packaging/Nix/dpsimpy.nix b/packaging/Nix/dpsimpy.nix new file mode 100644 index 0000000000..0332dc35b8 --- /dev/null +++ b/packaging/Nix/dpsimpy.nix @@ -0,0 +1,118 @@ +{ + lib, + + patchelf, + + cimpp, + cmake, + eigen, + fmt, + gsl, + nlohmann_json, + pkg-config, + python312, + python312Packages, + readerwriterqueue, + spdlog, + sundials321, + graphviz, + suitesparse-dpsim, + villas-node, + + cudatoolkit, + magma, + + # Options + withAllExtras ? true, + withOpenMP ? withAllExtras, + withCIMpp ? withAllExtras, + withVILLAS ? withAllExtras, + withGSL ? withAllExtras, + withGraphviz ? withAllExtras, + withPybind ? withAllExtras, + withSundials ? withAllExtras, + withSuiteSparse ? withAllExtras, + withMNASolverPlugin ? withAllExtras, +}: +with python312Packages; +buildPythonPackage { + name = "dpsimpy"; + src = ../..; + + nativeBuildInputs = [ + cmake + pkg-config + ]; + + pyproject = true; + + build-system = [ + setuptools + setuptools-scm + ]; + + dependencies = [ pytest-runner ]; + + buildInputs = + [ + eigen + fmt + spdlog + nlohmann_json + readerwriterqueue + + # TODO: Add these dependencies + # cudatoolkit + # magma + ] + ++ lib.optional withCIMpp cimpp + ++ lib.optional withVILLAS villas-node + ++ lib.optional withGSL gsl + ++ lib.optional withGraphviz graphviz + ++ lib.optional withSundials sundials321 + ++ lib.optional withSuiteSparse suitesparse-dpsim + ++ lib.optionals withPybind [ + python312 + python312Packages.pybind11 + ]; + + enableParallelBuilding = true; + dontUseCmakeConfigure = true; + + preBuild = '' + pypaBuildFlags+="-C--global-option=build_ext -C--global-option=--parallel=$NIX_BUILD_CORES" + ''; + + env = { + # NIX_DEBUG = "7"; + CMAKE_OPTS = builtins.concatStringsSep " " [ + # LTO is currently broken in Nixpkgs (https://github.com/NixOS/nixpkgs/issues/384599) + "-DWITH_LTO=OFF" + + "-DBUILD_SHARED_LIBS=ON" + + # Feature flags + "-DWITH_OPENMP=${if withOpenMP then "ON" else "OFF"}" + "-DWITH_CIM=${if withCIMpp then "ON" else "OFF"}" + "-DWITH_VILLAS=${if withVILLAS then "ON" else "OFF"}" + "-DWITH_GSL=${if withGSL then "ON" else "OFF"}" + "-DWITH_MNASOLVER_PLUGIN=${if withMNASolverPlugin then "ON" else "OFF"}" + + "-DDPSIM_BUILD_EXAMPLES=OFF" + + # We can not fetch external code within the Nix sandbox + # Instead we packaged those dependencies as separate Nix derivations. + "-DFETCH_EIGEN=OFF" + "-DFETCH_SUITESPARSE=OFF" + "-DFETCH_SPDLOG=OFF" + "-DFETCH_CIMPP=OFF" + "-DFETCH_PYBIND=OFF" + "-DFETCH_GRID_DATA=OFF" + "-DFETCH_FILESYSTEM=OFF" + "-DFETCH_JSON=OFF" + "-DFETCH_READERWRITERQUEUE=OFF" + + "-DCMAKE_SKIP_BUILD_RPATH=ON" + ]; + }; +} diff --git a/packaging/Nix/readerwriterqueue.nix b/packaging/Nix/readerwriterqueue.nix new file mode 100644 index 0000000000..7df5773cd4 --- /dev/null +++ b/packaging/Nix/readerwriterqueue.nix @@ -0,0 +1,24 @@ +{ + fetchFromGitHub, + stdenv, + cmake, +}: +stdenv.mkDerivation { + name = "readerwriterqueue"; + src = fetchFromGitHub { + owner = "cameron314"; + repo = "readerwriterqueue"; + rev = "16b48ae1148284e7b40abf72167206a4390a4592"; + hash = "sha256-m4cUIXiDFxTguDZ7d0svjlOSkUNYY0bbUp3t7adBwOo"; + }; + + enableParallelBuilding = true; + + nativeBuildInputs = [ cmake ]; + + cmakeFlags = [ "-DCMAKE_INSTALL_LIBDIR=lib" ]; + + # postInstall = '' + # cmake --install . --prefix "''${!outputDev}" --component Devel + # ''; +} diff --git a/packaging/Nix/shell.nix b/packaging/Nix/shell.nix new file mode 100644 index 0000000000..5e4e0a1b3c --- /dev/null +++ b/packaging/Nix/shell.nix @@ -0,0 +1,19 @@ +{ + mkShell, + dpsim, + python3, + pre-commit, + clang-tools, + ruby +}: +mkShell { + inputsFrom = [ dpsim ]; + + packages = [ + (python3.withPackages (ps: with ps; [ numpy ])) + + pre-commit + ruby # Required for pre-commit + clang-tools + ]; +} diff --git a/packaging/Nix/suitesparse.nix b/packaging/Nix/suitesparse.nix new file mode 100644 index 0000000000..3188759ee3 --- /dev/null +++ b/packaging/Nix/suitesparse.nix @@ -0,0 +1,14 @@ +{ fetchFromGitHub, suitesparse }: +suitesparse.overrideAttrs (oldAttrs: { + version = "5.10.6-dpsim"; + src = fetchFromGitHub { + owner = "dpsim-simulator"; + repo = "SuiteSparse"; + rev = "release-v5.10.6"; + hash = "sha256-KUUfy8eT+xj/GFAsGOvkTfQevNyUwH1rJcDOW5hO9mw"; + }; + + postPatch = '' + substituteInPlace ./KLU/Source/klu_print.c --replace 'KLU_dumpKLU' '// KLU_dumpKLU' + ''; +}) diff --git a/packaging/Nix/sundials.nix b/packaging/Nix/sundials.nix new file mode 100644 index 0000000000..5b0721a75d --- /dev/null +++ b/packaging/Nix/sundials.nix @@ -0,0 +1,19 @@ +{ + fetchFromGitHub, + sundials, + python2, +}: +(sundials.overrideAttrs ( + finalAttrs: prevAttrs: { + version = "3.2.1"; + src = fetchFromGitHub { + owner = "LLNL"; + repo = "sundials"; + rev = "v${finalAttrs.version}"; + hash = "sha256-5fVgxFEzhzw7rAENpt2+8qGR0pe00nntSFnyArmafzU"; + }; + + doCheck = false; + } +)).override + { python = python2; } diff --git a/packaging/Shell/install-fedora-deps-dev.sh b/packaging/Shell/install-fedora-deps-dev.sh index 1bf74946c8..4c608f046d 100644 --- a/packaging/Shell/install-fedora-deps-dev.sh +++ b/packaging/Shell/install-fedora-deps-dev.sh @@ -1,7 +1,7 @@ #!/bin/bash CIM_VERSION=${CIM_VERSION:-CGMES_2.4.15_16FEB2016} -VILLAS_VERSION=${VILLAS_VERSION:-66569cf9c43d2d7a4626b9a84321c4e340d3fe18} +VILLAS_VERSION=${VILLAS_VERSION:-5606793aaee2d1eeb663180d3e52718fa8bd5931} MAKE_PROCS=${MAKE_PROCS:-$(nproc)} MAKE_OPTS+="-j${MAKE_PROCS}" diff --git a/packaging/Shell/install-fedora-deps.sh b/packaging/Shell/install-fedora-deps.sh index 24e98ffd99..5c6e135392 100644 --- a/packaging/Shell/install-fedora-deps.sh +++ b/packaging/Shell/install-fedora-deps.sh @@ -1,7 +1,7 @@ #!/bin/bash CIM_VERSION=${CIM_VERSION:-CGMES_2.4.15_16FEB2016} -VILLAS_VERSION=${VILLAS_VERSION:-66569cf9c43d2d7a4626b9a84321c4e340d3fe18} +VILLAS_VERSION=${VILLAS_VERSION:-5606793aaee2d1eeb663180d3e52718fa8bd5931} MAKE_PROCS=${MAKE_PROCS:-$(nproc)} MAKE_OPTS+="-j${MAKE_PROCS}" @@ -72,6 +72,6 @@ cd /tmp && \ mkdir -p villas-node/build && cd villas-node/build && \ git checkout ${VILLAS_VERSION} && \ cmake ${CMAKE_OPTS} .. \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 && \ + -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 && \ make ${MAKE_OPTS} install && \ rm -rf /tmp/villas-node diff --git a/packaging/Shell/install-ubuntu-deps.sh b/packaging/Shell/install-ubuntu-deps.sh index 3ec1c2a23b..42e3e87fb8 100644 --- a/packaging/Shell/install-ubuntu-deps.sh +++ b/packaging/Shell/install-ubuntu-deps.sh @@ -1,7 +1,7 @@ #!/bin/bash CIM_VERSION=${CIM_VERSION:-CGMES_2.4.15_16FEB2016} -VILLAS_VERSION=${VILLAS_VERSION:-66569cf9c43d2d7a4626b9a84321c4e340d3fe18} +VILLAS_VERSION=${VILLAS_VERSION:-5606793aaee2d1eeb663180d3e52718fa8bd5931} MAKE_PROCS=${MAKE_PROCS:-$(nproc)} MAKE_OPTS+="-j${MAKE_PROCS}" @@ -58,6 +58,6 @@ cd /tmp && \ mkdir -p villas-node/build && cd villas-node/build && \ git checkout ${VILLAS_VERSION} && \ cmake ${CMAKE_OPTS} .. \ - -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 && \ + -DCMAKE_INSTALL_LIBDIR=/usr/local/lib64 && \ make ${MAKE_OPTS} install && \ rm -rf /tmp/villas-node diff --git a/pyproject.toml b/pyproject.toml index f23ef37807..3053afeea9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,9 @@ requires = ["setuptools>=42"] build-backend = "setuptools.build_meta" [tool.cibuildwheel] -build-verbosity = "3" -build="[cp]p3{8,9,10,11}-manylinux_x86_64" +build-verbosity = 3 +build = "cp3{9,10,11,12,13}-manylinux_x86_64" manylinux-x86_64-image = "sogno/dpsim:manylinux" -manylinux-pypy_x86_64-image = "sogno/dpsim:manylinux" + +[tool.pytest.ini_options] +filterwarnings = ["ignore::DeprecationWarning"] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 7d448c5c6c..0000000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -filterwarnings = ignore::DeprecationWarning \ No newline at end of file diff --git a/python/README.md b/python/README.md index 299f2c31ac..de08399d41 100644 --- a/python/README.md +++ b/python/README.md @@ -1 +1 @@ -This python package wraps the C++ core package of DPsim and includes pure python code that is convenient to use in combination with the simulation core. \ No newline at end of file +This Python package wraps the C++ core package of DPsim and includes pure Python code that is convenient to use in combination with the simulation core. diff --git a/python/src/dpsim/__init__.py b/python/src/dpsim/__init__.py index f8e7fe940c..009dd2fae8 100644 --- a/python/src/dpsim/__init__.py +++ b/python/src/dpsim/__init__.py @@ -4,6 +4,6 @@ try: from dpsimpy import * except ImportError: # pragma: no cover - print('Error: Could not find dpsim C++ module.') + print("Error: Could not find dpsim C++ module.") -__all__ = ['matpower'] +__all__ = ["matpower"] diff --git a/python/src/dpsim/matpower.py b/python/src/dpsim/matpower.py index 7914cd13c3..ceb29ec722 100644 --- a/python/src/dpsim/matpower.py +++ b/python/src/dpsim/matpower.py @@ -4,15 +4,14 @@ import dpsimpy -class Reader: - def __init__(self, mpc_file_path, mpc_name = 'mpc'): - # read input file (returns multidimensional dict) +class Reader: + def __init__(self, mpc_file_path, mpc_name="mpc"): + # Read input file (returns multidimensional dict) self.mpc_raw = scipy.io.loadmat(mpc_file_path) self.mpc_name = mpc_name def process_mpc(self): - version_idx = 0 base_pow_idx = 1 bus_data_idx = 2 @@ -26,7 +25,7 @@ def process_mpc(self): # System frequency (not included in mpc but needed for setting dpsimpy component parameters i.e inductances, capacitances ..) self.mpc_freq = 50 - self.mpc_omega = 2*np.pi*50 + self.mpc_omega = 2 * np.pi * 50 # Base power (MVA) self.mpc_base_power_MVA = self.mpc_raw[self.mpc_name][0][0][base_pow_idx][0][0] @@ -34,53 +33,98 @@ def process_mpc(self): #### Busses mpc_bus_raw = self.mpc_raw[self.mpc_name][0][0][bus_data_idx] - bus_data_header = ["bus_i", "type", "Pd", "Qd", "Gs", "Bs", "area", - "Vm", "Va", "baseKV", "zone", "Vmax", "Vmin"] - - self.mpc_bus_data = pd.DataFrame(mpc_bus_raw, columns = bus_data_header) + bus_data_header = [ + "bus_i", + "type", + "Pd", + "Qd", + "Gs", + "Bs", + "area", + "Vm", + "Va", + "baseKV", + "zone", + "Vmax", + "Vmin", + ] + + self.mpc_bus_data = pd.DataFrame(mpc_bus_raw, columns=bus_data_header) # scipy.io.loadmat loads all matrix entries as double. Convert specific columns back to int - self.mpc_bus_data['bus_i'] = self.mpc_bus_data['bus_i'].astype(int) - self.mpc_bus_data['type'] = self.mpc_bus_data['type'].astype(int) - self.mpc_bus_data['area'] = self.mpc_bus_data['area'].astype(int) - self.mpc_bus_data['zone'] = self.mpc_bus_data['zone'].astype(int) + self.mpc_bus_data["bus_i"] = self.mpc_bus_data["bus_i"].astype(int) + self.mpc_bus_data["type"] = self.mpc_bus_data["type"].astype(int) + self.mpc_bus_data["area"] = self.mpc_bus_data["area"].astype(int) + self.mpc_bus_data["zone"] = self.mpc_bus_data["zone"].astype(int) #### Generators mpc_gen_raw = self.mpc_raw[self.mpc_name][0][0][gen_data_idx] - gen_data_header = ["bus", "Pg", "Qg", "Qmax", "Qmin", "Vg", "mBase", "status", - "Pmax", "Pmin", "Pc1", "Pc2", "Qc1min", "Qc1max", "Qc2min", - "Qc2max", "ramp_agc", "ramp_10", "ramp_30", "ramp_q", "apf"] - - self.mpc_gen_data = pd.DataFrame(mpc_gen_raw, columns = gen_data_header) - - self.mpc_gen_data['bus'] = self.mpc_gen_data['bus'].astype(int) - self.mpc_gen_data['status'] = self.mpc_gen_data['status'].astype(int) + gen_data_header = [ + "bus", + "Pg", + "Qg", + "Qmax", + "Qmin", + "Vg", + "mBase", + "status", + "Pmax", + "Pmin", + "Pc1", + "Pc2", + "Qc1min", + "Qc1max", + "Qc2min", + "Qc2max", + "ramp_agc", + "ramp_10", + "ramp_30", + "ramp_q", + "apf", + ] + + self.mpc_gen_data = pd.DataFrame(mpc_gen_raw, columns=gen_data_header) + + self.mpc_gen_data["bus"] = self.mpc_gen_data["bus"].astype(int) + self.mpc_gen_data["status"] = self.mpc_gen_data["status"].astype(int) #### Branches - # extract only first 13 columns since following columns include results + # Extract only first 13 columns since following columns include results mpc_branch_raw = self.mpc_raw[self.mpc_name][0][0][branch_data_idx][:, :13] - branch_data_header = ["fbus", "tbus", "r", "x", "b", "rateA", "rateB", - "rateC", "ratio", "angle", "status", "angmin", "angmax"] - - self.mpc_branch_data = pd.DataFrame(mpc_branch_raw, columns = branch_data_header) - - self.mpc_branch_data['fbus'] = self.mpc_branch_data['fbus'].astype(int) - self.mpc_branch_data['tbus'] = self.mpc_branch_data['tbus'].astype(int) - self.mpc_branch_data['status'] = self.mpc_branch_data['status'].astype(int) + branch_data_header = [ + "fbus", + "tbus", + "r", + "x", + "b", + "rateA", + "rateB", + "rateC", + "ratio", + "angle", + "status", + "angmin", + "angmax", + ] + + self.mpc_branch_data = pd.DataFrame(mpc_branch_raw, columns=branch_data_header) + + self.mpc_branch_data["fbus"] = self.mpc_branch_data["fbus"].astype(int) + self.mpc_branch_data["tbus"] = self.mpc_branch_data["tbus"].astype(int) + self.mpc_branch_data["status"] = self.mpc_branch_data["status"].astype(int) #### TODO Generator costs def create_dpsim_objects(self): - self.process_mpc() - # return values: nodes and components + # Return values: nodes and components dpsimpy_busses_dict = {} dpsimpy_comp_dict = {} - # default multiplier for matpower data + # Default multiplier for matpower data mw_w = 1e6 kv_v = 1e3 @@ -91,157 +135,258 @@ def create_dpsim_objects(self): inj = 0 for index, bus in self.mpc_bus_data.iterrows(): - # create dpsimpy busses + # Create dpsimpy busses bus = bus + 1 - bus_index = str(self.mpc_bus_data.at[index,'bus_i']) + bus_index = str(self.mpc_bus_data.at[index, "bus_i"]) bus_name = bus_index - dpsimpy_busses_dict[bus_name] = dpsimpy.sp.SimNode(bus_name, dpsimpy.PhaseType.Single) + dpsimpy_busses_dict[bus_name] = dpsimpy.sp.SimNode( + bus_name, dpsimpy.PhaseType.Single + ) - # for each bus type create corresponding dpsimpy component + # For each bus type create corresponding dpsimpy component # 1 = PQ, 2 = PV, 3 = ref, 4 = isolated - bus_type = self.mpc_bus_data.at[index,'type'] + bus_type = self.mpc_bus_data.at[index, "type"] # Loads if bus_type == 1: load = load + 1 - load_name = "load%s" %load - load_p = self.mpc_bus_data.at[index,'Pd'] * mw_w - load_q = self.mpc_bus_data.at[index,'Qd'] * mw_w - load_baseV = self.mpc_bus_data.at[index,'baseKV'] * kv_v - - dpsimpy_comp_dict[load_name] = [dpsimpy.sp.ph1.Load(load_name, dpsimpy.LogLevel.info)] - dpsimpy_comp_dict[load_name][0].set_parameters(load_p, load_q, load_baseV) - dpsimpy_comp_dict[load_name][0].modify_power_flow_bus_type(dpsimpy.PowerflowBusType.PQ) - - # add connections - dpsimpy_comp_dict[load_name].append([dpsimpy_busses_dict[bus_index]]) # [to bus] + load_name = "load%s" % load + load_p = self.mpc_bus_data.at[index, "Pd"] * mw_w + load_q = self.mpc_bus_data.at[index, "Qd"] * mw_w + load_baseV = self.mpc_bus_data.at[index, "baseKV"] * kv_v + + dpsimpy_comp_dict[load_name] = [ + dpsimpy.sp.ph1.Load(load_name, dpsimpy.LogLevel.info) + ] + dpsimpy_comp_dict[load_name][0].set_parameters( + load_p, load_q, load_baseV + ) + dpsimpy_comp_dict[load_name][0].modify_power_flow_bus_type( + dpsimpy.PowerflowBusType.PQ + ) + + # Add connections + dpsimpy_comp_dict[load_name].append( + [dpsimpy_busses_dict[bus_index]] + ) # [to bus] # Generators elif bus_type == 2: generator = generator + 1 - gen_name = "gen%s" %generator - - # relevant data from self.mpc_gen_data. Identification with bus number available in mpc_bus_data and mpc_gen_data - gen = self.mpc_gen_data.loc[self.mpc_gen_data['bus'] == self.mpc_bus_data.at[index,'bus_i']] - - gen_baseS = gen['mBase']*mw_w # gen base MVA default is mpc.baseMVA - gen_baseV = self.mpc_bus_data.at[index,'baseKV']*kv_v # gen base kV - gen_v = gen['Vg']*gen_baseV # gen set point voltage (gen['Vg'] in p.u.) - gen_p = gen['Pg']*mw_w # gen ini. active power (gen['Pg'] in MVA) - # gen_q = gen['Qg']*mw_w # gen ini. reactive power (gen['Qg'] in MVAr) - gen_nom_s = abs(complex(gen['Pmax'], gen['Qmax'])) # gen nominal power (set default to mpc.baseMVA ? ) - - dpsimpy_comp_dict[gen_name] = [dpsimpy.sp.ph1.SynchronGenerator(gen_name, dpsimpy.LogLevel.info)] - dpsimpy_comp_dict[gen_name][0].set_parameters(gen_nom_s, gen_baseV, gen_p, gen_v, dpsimpy.PowerflowBusType.PV) + gen_name = "gen%s" % generator + + # Relevant data from self.mpc_gen_data. Identification with bus number available in mpc_bus_data and mpc_gen_data + gen = self.mpc_gen_data.loc[ + self.mpc_gen_data["bus"] == self.mpc_bus_data.at[index, "bus_i"] + ] + + gen_baseS = ( + gen["mBase"] * mw_w + ) # Generator base MVA default is mpc.baseMVA + gen_baseV = ( + self.mpc_bus_data.at[index, "baseKV"] * kv_v + ) # Generator base kV + gen_v = ( + gen["Vg"] * gen_baseV + ) # Generator set point voltage (gen['Vg'] in p.u.) + gen_p = ( + gen["Pg"] * mw_w + ) # Generator ini. active power (gen['Pg'] in MVA) + # gen_q = gen['Qg']*mw_w # Generator ini. reactive power (gen['Qg'] in MVAr) + gen_nom_s = abs( + complex(gen["Pmax"], gen["Qmax"]) + ) # Generator nominal power (set default to mpc.baseMVA ?) + + dpsimpy_comp_dict[gen_name] = [ + dpsimpy.sp.ph1.SynchronGenerator(gen_name, dpsimpy.LogLevel.info) + ] + dpsimpy_comp_dict[gen_name][0].set_parameters( + gen_nom_s, gen_baseV, gen_p, gen_v, dpsimpy.PowerflowBusType.PV + ) dpsimpy_comp_dict[gen_name][0].set_base_voltage(gen_baseV) - # add connections - dpsimpy_comp_dict[gen_name].append([dpsimpy_busses_dict[bus_index]]) # [to bus] + # Add connections + dpsimpy_comp_dict[gen_name].append( + [dpsimpy_busses_dict[bus_index]] + ) # [to bus] # Network injection (slack bus) elif bus_type == 3: inj = inj + 1 - extnet_name = "extnet%s" %inj + extnet_name = "extnet%s" % inj - # relevant data from self.mpc_gen_data. Identification with bus number available in mpc_bus_data and mpc_gen_data - extnet = self.mpc_gen_data.loc[self.mpc_gen_data['bus'] == self.mpc_bus_data.at[index,'bus_i']] + # Relevant data from self.mpc_gen_data. Identification with bus number available in mpc_bus_data and mpc_gen_data + extnet = self.mpc_gen_data.loc[ + self.mpc_gen_data["bus"] == self.mpc_bus_data.at[index, "bus_i"] + ] - # extnet_baseS= extnet['mBase']*mw_w # default is mpc.baseMVA - extnet_baseV = self.mpc_bus_data.at[index,'baseKV']*kv_v - extnet_v = extnet['Vg']*extnet_baseV + # extnet_baseS = extnet['mBase']*mw_w # Default is mpc.baseMVA + extnet_baseV = self.mpc_bus_data.at[index, "baseKV"] * kv_v + extnet_v = extnet["Vg"] * extnet_baseV - dpsimpy_comp_dict[extnet_name] = [dpsimpy.sp.ph1.NetworkInjection(extnet_name, dpsimpy.LogLevel.info)] + dpsimpy_comp_dict[extnet_name] = [ + dpsimpy.sp.ph1.NetworkInjection(extnet_name, dpsimpy.LogLevel.info) + ] dpsimpy_comp_dict[extnet_name][0].set_parameters(extnet_v) dpsimpy_comp_dict[extnet_name][0].set_base_voltage(extnet_baseV) - dpsimpy_comp_dict[extnet_name][0].modify_power_flow_bus_type(dpsimpy.PowerflowBusType.VD) + dpsimpy_comp_dict[extnet_name][0].modify_power_flow_bus_type( + dpsimpy.PowerflowBusType.VD + ) - # add connections - dpsimpy_comp_dict[extnet_name].append([dpsimpy_busses_dict[bus_index]]) # [to bus] + # Add connections + dpsimpy_comp_dict[extnet_name].append( + [dpsimpy_busses_dict[bus_index]] + ) # [to bus] - #isolated + # Isolated elif bus_type == 4: print("isolated bus type") else: print("bus type error") - ### branches #### + ### Branches line = 0 trafo = 0 for index, branch in self.mpc_branch_data.iterrows(): - - branch_ratio = self.mpc_branch_data.at[index,'ratio'] + branch_ratio = self.mpc_branch_data.at[index, "ratio"] # Lines if branch_ratio == 0: line = line + 1 - line_name = "line%s_%s-%s" %(line, self.mpc_branch_data.at[index,'fbus'] , self.mpc_branch_data.at[index,'tbus']) - - line_fbus = self.mpc_branch_data.at[index,'fbus'] - line_tbus = self.mpc_branch_data.at[index,'tbus'] - - tmp_fbus = self.mpc_bus_data.loc[self.mpc_bus_data['bus_i'] == line_fbus] - tmp_tbus = self.mpc_bus_data.loc[self.mpc_bus_data['bus_i'] == line_tbus] - - line_fbus_baseV = self.mpc_bus_data.at[tmp_fbus.first_valid_index(),'baseKV']*kv_v - line_tbus_baseV = self.mpc_bus_data.at[tmp_tbus.first_valid_index(),'baseKV']*kv_v - - line_baseZ = line_tbus_baseV*line_tbus_baseV / (self.mpc_base_power_MVA*mw_w) - line_r = self.mpc_branch_data.at[index,'r'] * line_baseZ - line_x = self.mpc_branch_data.at[index,'x'] * line_baseZ - line_b = self.mpc_branch_data.at[index,'b'] / line_baseZ + line_name = "line%s_%s-%s" % ( + line, + self.mpc_branch_data.at[index, "fbus"], + self.mpc_branch_data.at[index, "tbus"], + ) + + line_fbus = self.mpc_branch_data.at[index, "fbus"] + line_tbus = self.mpc_branch_data.at[index, "tbus"] + + tmp_fbus = self.mpc_bus_data.loc[ + self.mpc_bus_data["bus_i"] == line_fbus + ] + tmp_tbus = self.mpc_bus_data.loc[ + self.mpc_bus_data["bus_i"] == line_tbus + ] + + line_fbus_baseV = ( + self.mpc_bus_data.at[tmp_fbus.first_valid_index(), "baseKV"] * kv_v + ) + line_tbus_baseV = ( + self.mpc_bus_data.at[tmp_tbus.first_valid_index(), "baseKV"] * kv_v + ) + + line_baseZ = ( + line_tbus_baseV * line_tbus_baseV / (self.mpc_base_power_MVA * mw_w) + ) + line_r = self.mpc_branch_data.at[index, "r"] * line_baseZ + line_x = self.mpc_branch_data.at[index, "x"] * line_baseZ + line_b = self.mpc_branch_data.at[index, "b"] / line_baseZ line_l = line_x / self.mpc_omega line_c = line_b / self.mpc_omega - line_g = 0 # line conductance is not included in mpc - - dpsimpy_comp_dict[line_name] = [dpsimpy.sp.ph1.PiLine(line_name, dpsimpy.LogLevel.info)] - dpsimpy_comp_dict[line_name][0].set_parameters(line_r, line_l, line_c, line_g) + line_g = 0 # Line conductance is not included in mpc + + dpsimpy_comp_dict[line_name] = [ + dpsimpy.sp.ph1.PiLine(line_name, dpsimpy.LogLevel.info) + ] + dpsimpy_comp_dict[line_name][0].set_parameters( + line_r, line_l, line_c, line_g + ) dpsimpy_comp_dict[line_name][0].set_base_voltage(line_tbus_baseV) - # add connections - dpsimpy_comp_dict[line_name].append([dpsimpy_busses_dict[str(line_fbus)], dpsimpy_busses_dict[str(line_tbus)]]) + + # Add connections + dpsimpy_comp_dict[line_name].append( + [ + dpsimpy_busses_dict[str(line_fbus)], + dpsimpy_busses_dict[str(line_tbus)], + ] + ) # Transformers else: trafo = trafo + 1 - transf_name = "transformer%s_%s-%s" %(trafo, self.mpc_branch_data.at[index,'fbus'] , self.mpc_branch_data.at[index,'tbus']) - transf_s = self.mpc_branch_data.at[index,'rateA']*mw_w # Matpower: Used to specify branch flow limits. By default these are limits on apparent power with units in MV - - transf_fbus = self.mpc_branch_data.at[index,'fbus'] - transf_tbus = self.mpc_branch_data.at[index,'tbus'] - - tmp_fbus = self.mpc_bus_data.loc[self.mpc_bus_data['bus_i'] == transf_fbus] - tmp_tbus = self.mpc_bus_data.loc[self.mpc_bus_data['bus_i'] == transf_tbus] - - - transf_fbus_baseV = self.mpc_bus_data.at[tmp_fbus.first_valid_index(),'baseKV']*kv_v - transf_tbus_baseV = self.mpc_bus_data.at[tmp_tbus.first_valid_index(),'baseKV']*kv_v - - transf_primary_v = self.mpc_bus_data.at[tmp_fbus.first_valid_index(),'Vm']*transf_fbus_baseV - transf_secondary_v = self.mpc_bus_data.at[tmp_tbus.first_valid_index(),'Vm']*transf_tbus_baseV - - transf_offNom_ratio = self.mpc_branch_data.at[index,'ratio'] - transf_primary_v = transf_primary_v/ transf_offNom_ratio + transf_name = "transformer%s_%s-%s" % ( + trafo, + self.mpc_branch_data.at[index, "fbus"], + self.mpc_branch_data.at[index, "tbus"], + ) + transf_s = ( + self.mpc_branch_data.at[index, "rateA"] * mw_w + ) # Matpower: Used to specify branch flow limits. By default these are limits on apparent power with units in MV + + transf_fbus = self.mpc_branch_data.at[index, "fbus"] + transf_tbus = self.mpc_branch_data.at[index, "tbus"] + + tmp_fbus = self.mpc_bus_data.loc[ + self.mpc_bus_data["bus_i"] == transf_fbus + ] + tmp_tbus = self.mpc_bus_data.loc[ + self.mpc_bus_data["bus_i"] == transf_tbus + ] + + transf_fbus_baseV = ( + self.mpc_bus_data.at[tmp_fbus.first_valid_index(), "baseKV"] * kv_v + ) + transf_tbus_baseV = ( + self.mpc_bus_data.at[tmp_tbus.first_valid_index(), "baseKV"] * kv_v + ) + + transf_primary_v = ( + self.mpc_bus_data.at[tmp_fbus.first_valid_index(), "Vm"] + * transf_fbus_baseV + ) + transf_secondary_v = ( + self.mpc_bus_data.at[tmp_tbus.first_valid_index(), "Vm"] + * transf_tbus_baseV + ) + + transf_offNom_ratio = self.mpc_branch_data.at[index, "ratio"] + transf_primary_v = transf_primary_v / transf_offNom_ratio transf_ratio = transf_primary_v / transf_secondary_v - - transf_baseZ = transf_tbus_baseV*transf_tbus_baseV / (self.mpc_base_power_MVA*mw_w) - transf_r = self.mpc_branch_data.at[index,'r']* transf_baseZ - transf_x = self.mpc_branch_data.at[index,'x']* transf_baseZ + transf_baseZ = ( + transf_tbus_baseV + * transf_tbus_baseV + / (self.mpc_base_power_MVA * mw_w) + ) + transf_r = self.mpc_branch_data.at[index, "r"] * transf_baseZ + transf_x = self.mpc_branch_data.at[index, "x"] * transf_baseZ transf_l = transf_x / self.mpc_omega - dpsimpy_comp_dict[transf_name] = [dpsimpy.sp.ph1.Transformer(transf_name, dpsimpy.LogLevel.info)] - dpsimpy_comp_dict[transf_name][0].set_parameters(transf_primary_v, transf_secondary_v, np.abs(transf_ratio), np.angle(transf_ratio), transf_r, transf_l) + dpsimpy_comp_dict[transf_name] = [ + dpsimpy.sp.ph1.Transformer(transf_name, dpsimpy.LogLevel.info) + ] + dpsimpy_comp_dict[transf_name][0].set_parameters( + transf_primary_v, + transf_secondary_v, + np.abs(transf_ratio), + np.angle(transf_ratio), + transf_r, + transf_l, + ) dpsimpy_comp_dict[transf_name][0].set_base_voltage(transf_tbus_baseV) - print(transf_primary_v, transf_secondary_v, np.abs(transf_ratio), np.angle(transf_ratio), transf_r, transf_l) + print( + transf_primary_v, + transf_secondary_v, + np.abs(transf_ratio), + np.angle(transf_ratio), + transf_r, + transf_l, + ) print(transf_tbus_baseV) - # add connections - dpsimpy_comp_dict[transf_name].append([dpsimpy_busses_dict[str(transf_fbus)], dpsimpy_busses_dict[str(transf_tbus)]]) + # Add connections + dpsimpy_comp_dict[transf_name].append( + [ + dpsimpy_busses_dict[str(transf_fbus)], + dpsimpy_busses_dict[str(transf_tbus)], + ] + ) return dpsimpy_busses_dict, dpsimpy_comp_dict def load_mpc(self): - dpsimpy_busses_dict, dpsimpy_comp_dict = self.create_dpsim_objects() system_comp = [] @@ -263,4 +408,3 @@ def load_mpc(self): system = dpsimpy.SystemTopology(self.mpc_freq, system_nodes, system_comp) return system - diff --git a/scripts/start_jupyter.sh b/scripts/start_jupyter.sh index 81dfdb1b4c..c5998cfb62 100644 --- a/scripts/start_jupyter.sh +++ b/scripts/start_jupyter.sh @@ -3,4 +3,4 @@ cd /dpsim-dev/dpsim/build export PYTHONPATH="$(pwd)/Source/Python:$(pwd)/../Source/Python" cd /dpsim-dev/dpsim -jupyter lab --ip="0.0.0.0" --allow-root --no-browser \ No newline at end of file +jupyter lab --ip="0.0.0.0" --allow-root --no-browser diff --git a/setup.cfg b/setup.cfg index d2c07643a4..e6ca8df9d6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,8 +1,8 @@ [metadata] name = dpsim -version = 1.1.1 +version = 1.2.1 author = The DPsim Authors -author_email = mmirz@eonerc.rwth-aachen.de +author_email = post_acs@eonerc.rwth-aachen.de description = dynamic real-time power system simulator long_description = file: README.md long_description_content_type = text/markdown diff --git a/setup.py b/setup.py index c9b1ddecea..4046eec991 100644 --- a/setup.py +++ b/setup.py @@ -1,82 +1,81 @@ import os -import re import sys import platform import subprocess from setuptools import setup, find_packages, Extension from setuptools.command.build_ext import build_ext -from distutils.version import LooseVersion class CMakeExtension(Extension): def __init__(self, name): Extension.__init__(self, name, sources=[]) + class CMakeBuild(build_ext): def build_extension(self, ext): - extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) - debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug - cfg = 'Debug' if self.debug else 'Release' - print('building CMake extension in %s configuration' % cfg) + cfg = "Debug" if self.debug else "Release" + print("building CMake extension in %s configuration" % cfg) cmake_args = [ f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}", f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG={extdir}", f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE={extdir}", f"-DPYTHON_EXECUTABLE={sys.executable}", - f"-DCMAKE_BUILD_TYPE={cfg}" # not used on MSVC, but no harm + f"-DCMAKE_BUILD_TYPE={cfg}", # Not used on MSVC, but no harm + "-DCMAKE_POLICY_VERSION_MINIMUM=3.5", ] - if platform.system() == 'Windows': - cmake_args += ['-A', 'x64'] - build_args = ['--', '/m'] + if platform.system() == "Windows": + cmake_args += ["-A", "x64"] + build_args = ["--", "/m"] else: if self.parallel: - build_args = ['--', '-j' + str(self.parallel)] + build_args = ["--", "-j" + str(self.parallel)] else: - build_args = ['--', '-j4'] + build_args = ["--", "-j4"] if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) env = os.environ.copy() - if env.get('CMAKE_OPTS'): - cmake_args += env.get('CMAKE_OPTS').split(' ') + if env.get("CMAKE_OPTS"): + cmake_args += env.get("CMAKE_OPTS").split(" ") # CMakeLists.txt is in the same directory as this setup.py file sourcedir = os.path.abspath(os.path.dirname(__file__)) - print(' '.join(['cmake', sourcedir] + cmake_args)) + print(" ".join(["cmake", sourcedir] + cmake_args)) subprocess.check_call( - ['cmake', sourcedir] + cmake_args, cwd=self.build_temp, env=env + ["cmake", sourcedir] + cmake_args, cwd=self.build_temp, env=env ) - print(' '.join(['cmake', '--build', '.', '--target', 'dpsimpy'] + build_args)) + print( + " ".join( + ["cmake", "--build", ".", "--target", "dpsimpy", "dpsimpyvillas"] + + build_args + ) + ) subprocess.check_call( - ['cmake', '--build', '.', '--target', 'dpsimpy'] + build_args, cwd=self.build_temp + ["cmake", "--build", ".", "--target", "dpsimpy", "dpsimpyvillas"] + + build_args, + cwd=self.build_temp, ) + setup( - packages=find_packages('python/src'), + packages=find_packages("python/src"), package_dir={"dpsim": "python/src/dpsim"}, - python_requires=">=3.8", - setup_requires=[ - 'pytest-runner', - 'wheel' - ], - tests_require=[ - 'pytest', - 'pyyaml', - 'nbformat', - 'nbconvert' - ], - ext_modules=[ - CMakeExtension('dpsimpy') + python_requires=">=3.9", + install_requires=[ + "numpy>=2.0.0", + "pandas>=2.0.0", + "scipy>=1.10.0", ], - cmdclass={ - 'build_ext': CMakeBuild - }, - zip_safe=False + setup_requires=["pytest-runner", "wheel"], + tests_require=["pytest", "pyyaml", "nbformat", "nbconvert"], + ext_modules=[CMakeExtension("dpsimpy"), CMakeExtension("dpsimpyvillas")], + cmdclass={"build_ext": CMakeBuild}, + zip_safe=False, ) diff --git a/sonar-project.properties b/sonar-project.properties index 3a918355ea..a06b6c77c2 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,14 +7,14 @@ sonar.cfamily.analysisCache.path=sonar-cache sonar.cfamily.analysisCache.mode=fs # Sonar Python Version -sonar.python.version=3.8, 3.9, 3.10 +sonar.python.version=3.9, 3.10, 3.11, 3.12, 3.13, 3.14 # Patterns excluded from duplication detection sonar.cpd.exclusions=dpsim/examples/**/*,examples/**/* # This is the name and version displayed in the SonarCloud UI. sonar.projectName=DPsim -sonar.projectVersion=1.1.1 +sonar.projectVersion=1.2.1 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. #sonar.sources=.