{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Problem 5.1\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Integrated Energy Grids**\n", "\n", "**Problem 5.1**\n", "\n", "**Assume we have three buses (Denmark, Netherlands and Germany) with nominal voltage $V_{nom}$= 2000 V connected by three transmission lines. In the bus, Denmark there is a wind generator that is producing 100 MW. In the bus Germany, there is a load that is consuming 100 MW of active power and 100 MVAR of reactive power. The transmission lines DK-NL and NL-GE have a unitary resistance $r$=0.01 and reactance $x$=0.1. The transmission lines DK-GE has a unitary resistance $r$=0.02 and reactance $x$=0.1. Using Python for Power System Analysis (PyPSA):**\n", "\n", "**a) Calculate the power flows along the transmission lines using AC power flow representation.**\n", "\n", "**b) Calculate the power flows along the transmission lines using a linearized approximation (also known as DC optimal power flow) and discuss the results.**\n", "\n", "_Hint: It is recommended to follow the [PyPSA tutorial](https://martavp.github.io/integrated-energy-grids/intro-pypsa.html#) before trying this problem._" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{note}\n", "If you have not yet set up Python on your computer, you can execute this tutorial in your browser via [Google Colab](https://colab.research.google.com/). Click on the rocket in the top right corner and launch \"Colab\". If that doesn't work download the `.ipynb` file and import it in [Google Colab](https://colab.research.google.com/).\n", "\n", "Then install the following packages by executing the following command in a Jupyter cell at the top of the notebook.\n", "\n", "```sh\n", "!pip install numpy pypsa\n", "```\n", ":::" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pypsa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start by creating the network object and adding the three buses corresponding to Denmark, Netherlands and Germany. \n", "The added buses can be printed using network.buses" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "network = pypsa.Network()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
v_nomtypexycarrierunitv_mag_pu_setv_mag_pu_minv_mag_pu_maxcontrolgeneratorsub_network
Bus
bus Denmark2000.00.00.0AC1.00.0infPQ
bus Netherlands2000.00.00.0AC1.00.0infPQ
bus Germany2000.00.00.0AC1.00.0infPQ
\n", "
" ], "text/plain": [ " v_nom type x y carrier unit v_mag_pu_set \\\n", "Bus \n", "bus Denmark 2000.0 0.0 0.0 AC 1.0 \n", "bus Netherlands 2000.0 0.0 0.0 AC 1.0 \n", "bus Germany 2000.0 0.0 0.0 AC 1.0 \n", "\n", " v_mag_pu_min v_mag_pu_max control generator sub_network \n", "Bus \n", "bus Denmark 0.0 inf PQ \n", "bus Netherlands 0.0 inf PQ \n", "bus Germany 0.0 inf PQ " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.add(\"Bus\", \"bus Denmark\", v_nom=2000.0)\n", "network.add(\"Bus\", \"bus Netherlands\", v_nom=2000.0)\n", "network.add(\"Bus\", \"bus Germany\", v_nom=2000.0)\n", "\n", "network.buses" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We add the three lines connecting the buses" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
bus0bus1typexrgbs_noms_nom_mods_nom_extendable...v_ang_minv_ang_maxsub_networkx_pur_pug_pub_pux_pu_effr_pu_effs_nom_opt
Line
line DK-NLbus Denmarkbus Netherlands0.10.010.00.00.00.0False...-infinf0.00.00.00.00.00.00.0
line DK-DEbus Denmarkbus Germany0.10.020.00.00.00.0False...-infinf0.00.00.00.00.00.00.0
line NL-DEbus Netherlandsbus Germany0.10.010.00.00.00.0False...-infinf0.00.00.00.00.00.00.0
\n", "

3 rows × 31 columns

\n", "
" ], "text/plain": [ " bus0 bus1 type x r g b s_nom \\\n", "Line \n", "line DK-NL bus Denmark bus Netherlands 0.1 0.01 0.0 0.0 0.0 \n", "line DK-DE bus Denmark bus Germany 0.1 0.02 0.0 0.0 0.0 \n", "line NL-DE bus Netherlands bus Germany 0.1 0.01 0.0 0.0 0.0 \n", "\n", " s_nom_mod s_nom_extendable ... v_ang_min v_ang_max \\\n", "Line ... \n", "line DK-NL 0.0 False ... -inf inf \n", "line DK-DE 0.0 False ... -inf inf \n", "line NL-DE 0.0 False ... -inf inf \n", "\n", " sub_network x_pu r_pu g_pu b_pu x_pu_eff r_pu_eff s_nom_opt \n", "Line \n", "line DK-NL 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", "line DK-DE 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", "line NL-DE 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", "\n", "[3 rows x 31 columns]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.add(\"Line\",\" line DK-NL\", bus0 = \"bus Denmark\", bus1= \"bus Netherlands\", x=0.1, r=0.01)\n", "network.add(\"Line\",\" line DK-DE\", bus0 = \"bus Denmark\", bus1= \"bus Germany\", x=0.1, r=0.02)\n", "network.add(\"Line\",\" line NL-DE\", bus0 = \"bus Netherlands\", bus1= \"bus Germany\", x=0.1, r=0.01)\n", "\n", "network.lines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add a generator at the Denmark bus." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
buscontroltypep_nomp_nom_modp_nom_extendablep_nom_minp_nom_maxp_min_pup_max_pu...min_up_timemin_down_timeup_time_beforedown_time_beforeramp_limit_upramp_limit_downramp_limit_start_upramp_limit_shut_downweightp_nom_opt
Generator
generator Denmarkbus DenmarkPQ0.00.0False0.0inf0.01.0...0010NaNNaN1.01.01.00.0
\n", "

1 rows × 37 columns

\n", "
" ], "text/plain": [ " bus control type p_nom p_nom_mod \\\n", "Generator \n", "generator Denmark bus Denmark PQ 0.0 0.0 \n", "\n", " p_nom_extendable p_nom_min p_nom_max p_min_pu p_max_pu \\\n", "Generator \n", "generator Denmark False 0.0 inf 0.0 1.0 \n", "\n", " ... min_up_time min_down_time up_time_before \\\n", "Generator ... \n", "generator Denmark ... 0 0 1 \n", "\n", " down_time_before ramp_limit_up ramp_limit_down \\\n", "Generator \n", "generator Denmark 0 NaN NaN \n", "\n", " ramp_limit_start_up ramp_limit_shut_down weight \\\n", "Generator \n", "generator Denmark 1.0 1.0 1.0 \n", "\n", " p_nom_opt \n", "Generator \n", "generator Denmark 0.0 \n", "\n", "[1 rows x 37 columns]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.add(\"Generator\", \n", " \"generator Denmark\", \n", " bus=\"bus Denmark\",\n", " p_set=100)\n", "network.generators" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Generator\n", "generator Denmark 100.0\n", "Name: p_set, dtype: float64" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.generators.p_set" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add a load at the Germany bus" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
buscarriertypep_setq_setsignactive
Load
load Germanybus Germany100.0100.0-1.0True
\n", "
" ], "text/plain": [ " bus carrier type p_set q_set sign active\n", "Load \n", "load Germany bus Germany 100.0 100.0 -1.0 True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.add(\"Load\", \n", " \"load Germany\", \n", " bus=\"bus Germany\", \n", " p_set=100,\n", " q_set=100)\n", "network.loads" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now solve the non-linear power flow using a Newton-Raphson method." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network for snapshots Index(['now'], dtype='object', name='snapshot')\n" ] }, { "data": { "text/plain": [ "{'n_iter': SubNetwork 0\n", " snapshot \n", " now 2,\n", " 'error': SubNetwork 0\n", " snapshot \n", " now 8.204964e-09,\n", " 'converged': SubNetwork 0\n", " snapshot \n", " now True}" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.pf()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ok, the solution converge, we can check now the active power flow on the lines." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
line DK-NLline DK-DEline NL-DE
snapshot
now31.44105968.55899631.441054
\n", "
" ], "text/plain": [ " line DK-NL line DK-DE line NL-DE\n", "snapshot \n", "now 31.441059 68.558996 31.441054" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.lines_t.p0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also check the voltage angles on the buses. We need to apply a conversion factor if we want to show them in degrees." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Busbus Denmarkbus Netherlandsbus Germany
snapshot
now0.0-0.00004-0.00008
\n", "
" ], "text/plain": [ "Bus bus Denmark bus Netherlands bus Germany\n", "snapshot \n", "now 0.0 -0.00004 -0.00008" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.buses_t.v_ang * 180 / np.pi" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and their per-unit magnitudes" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Busbus Denmarkbus Netherlandsbus Germany
snapshot
now1.00.9999990.999998
\n", "
" ], "text/plain": [ "Bus bus Denmark bus Netherlands bus Germany\n", "snapshot \n", "now 1.0 0.999999 0.999998" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.buses_t.v_mag_pu" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**b) Calculate the power flows along the transmission lines using a linearized approximation (DC optimal power flow).**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use linear power flows and get a similar solution" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:pypsa.pf:Performing linear load-flow on AC sub-network for snapshot(s) Index(['now'], dtype='object', name='snapshot')\n" ] } ], "source": [ "network.lpf()" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
line DK-NLline DK-DEline NL-DE
snapshot
now33.33333366.66666733.333333
\n", "
" ], "text/plain": [ " line DK-NL line DK-DE line NL-DE\n", "snapshot \n", "now 33.333333 66.666667 33.333333" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "network.lines_t.p0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this simple case, the solution that we obtain are very similar." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "@webio": { "lastCommId": null, "lastKernelId": null }, "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.8" } }, "nbformat": 4, "nbformat_minor": 4 }