{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Problem 5.4 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Integrated Energy Grids**\n",
"\n",
"**Problem 5.4**\n",
"\n",
"**Assume we have three buses (Denmark, Sweden, and Norway) with nominal voltage $V_{nom}$= 2000 V connected by three transmission lines. In each of the buses, there is a gas power generator whose variable cost is 50 EUR/MWh and installed capacity is 50 MW. In the Denmark bus, there is a wind generator whose variable cost is zero and whose installed capacity is 200 MW. The transmission lines have a unitary resistance $r$=0.01 and reactance $x$=0.1, and nominal capacity $S_{nom}=100$ VA. The demand is 50 MW for Denmark and Sweden and 30 MW for Norway. Using Python for Power System Analysis (PyPSA):**\n",
"\n",
"**a) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the power flows along the transmission lines using AC power flow representation.**\n",
"\n",
"**b) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the power flows along the transmission lines using a linearized approximation (also known as DC optimal power flow).**\n",
"\n",
"**c) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the power flows along the transmission lines using the Net Transfer Capacity (NTC) approach for the transmission lines and discuss the results.**"
]
},
{
"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, Sweden, and Norway. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"network = pypsa.Network()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" v_nom | \n",
" type | \n",
" x | \n",
" y | \n",
" carrier | \n",
" unit | \n",
" v_mag_pu_set | \n",
" v_mag_pu_min | \n",
" v_mag_pu_max | \n",
" control | \n",
" generator | \n",
" sub_network | \n",
"
\n",
" \n",
" Bus | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" bus Denmark | \n",
" 2000.0 | \n",
" | \n",
" 0.0 | \n",
" 0.0 | \n",
" AC | \n",
" | \n",
" 1.0 | \n",
" 0.0 | \n",
" inf | \n",
" PQ | \n",
" | \n",
" | \n",
"
\n",
" \n",
" bus Sweden | \n",
" 2000.0 | \n",
" | \n",
" 0.0 | \n",
" 0.0 | \n",
" AC | \n",
" | \n",
" 1.0 | \n",
" 0.0 | \n",
" inf | \n",
" PQ | \n",
" | \n",
" | \n",
"
\n",
" \n",
" bus Norway | \n",
" 2000.0 | \n",
" | \n",
" 0.0 | \n",
" 0.0 | \n",
" AC | \n",
" | \n",
" 1.0 | \n",
" 0.0 | \n",
" inf | \n",
" PQ | \n",
" | \n",
" | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" v_nom type x y carrier unit v_mag_pu_set v_mag_pu_min \\\n",
"Bus \n",
"bus Denmark 2000.0 0.0 0.0 AC 1.0 0.0 \n",
"bus Sweden 2000.0 0.0 0.0 AC 1.0 0.0 \n",
"bus Norway 2000.0 0.0 0.0 AC 1.0 0.0 \n",
"\n",
" v_mag_pu_max control generator sub_network \n",
"Bus \n",
"bus Denmark inf PQ \n",
"bus Sweden inf PQ \n",
"bus Norway inf PQ "
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for node in [\"Denmark\", \"Sweden\", \"Norway\"]:\n",
" network.add(\"Bus\", \"bus {}\".format(node), v_nom=2000)\n",
"\n",
"network.buses"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We add the three lines connecting the buses"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" bus0 | \n",
" bus1 | \n",
" type | \n",
" x | \n",
" r | \n",
" g | \n",
" b | \n",
" s_nom | \n",
" s_nom_mod | \n",
" s_nom_extendable | \n",
" ... | \n",
" v_ang_min | \n",
" v_ang_max | \n",
" sub_network | \n",
" x_pu | \n",
" r_pu | \n",
" g_pu | \n",
" b_pu | \n",
" x_pu_eff | \n",
" r_pu_eff | \n",
" s_nom_opt | \n",
"
\n",
" \n",
" Line | \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",
" line DK-SW | \n",
" bus Denmark | \n",
" bus Sweden | \n",
" | \n",
" 0.1 | \n",
" 0.01 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 100.0 | \n",
" 0.0 | \n",
" False | \n",
" ... | \n",
" -inf | \n",
" inf | \n",
" | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" line DK-NO | \n",
" bus Denmark | \n",
" bus Norway | \n",
" | \n",
" 0.1 | \n",
" 0.01 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 100.0 | \n",
" 0.0 | \n",
" False | \n",
" ... | \n",
" -inf | \n",
" inf | \n",
" | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" line SW-NO | \n",
" bus Sweden | \n",
" bus Norway | \n",
" | \n",
" 0.1 | \n",
" 0.01 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 100.0 | \n",
" 0.0 | \n",
" False | \n",
" ... | \n",
" -inf | \n",
" inf | \n",
" | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
3 rows × 31 columns
\n",
"
"
],
"text/plain": [
" bus0 bus1 type x r g b s_nom \\\n",
"Line \n",
"line DK-SW bus Denmark bus Sweden 0.1 0.01 0.0 0.0 100.0 \n",
"line DK-NO bus Denmark bus Norway 0.1 0.01 0.0 0.0 100.0 \n",
"line SW-NO bus Sweden bus Norway 0.1 0.01 0.0 0.0 100.0 \n",
"\n",
" s_nom_mod s_nom_extendable ... v_ang_min v_ang_max \\\n",
"Line ... \n",
"line DK-SW 0.0 False ... -inf inf \n",
"line DK-NO 0.0 False ... -inf inf \n",
"line SW-NO 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-SW 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"line DK-NO 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"line SW-NO 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"\n",
"[3 rows x 31 columns]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.add(\"Line\", \"line DK-SW\", bus0 = \"bus Denmark\", bus1 = \"bus Sweden\", s_nom = 100, x=0.1, r=0.01)\n",
"network.add(\"Line\", \"line DK-NO\", bus0 = \"bus Denmark\", bus1 = \"bus Norway\", s_nom = 100, x=0.1, r=0.01)\n",
"network.add(\"Line\", \"line SW-NO\", bus0 = \"bus Sweden\", bus1 = \"bus Norway\", s_nom = 100, x=0.1, r=0.01)\n",
"\n",
"network.lines"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We add the generators"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" bus | \n",
" control | \n",
" type | \n",
" p_nom | \n",
" p_nom_mod | \n",
" p_nom_extendable | \n",
" p_nom_min | \n",
" p_nom_max | \n",
" p_min_pu | \n",
" p_max_pu | \n",
" ... | \n",
" min_up_time | \n",
" min_down_time | \n",
" up_time_before | \n",
" down_time_before | \n",
" ramp_limit_up | \n",
" ramp_limit_down | \n",
" ramp_limit_start_up | \n",
" ramp_limit_shut_down | \n",
" weight | \n",
" p_nom_opt | \n",
"
\n",
" \n",
" Generator | \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",
" gas Denmark | \n",
" bus Denmark | \n",
" PQ | \n",
" | \n",
" 50.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 1.0 | \n",
" ... | \n",
" 0 | \n",
" 0 | \n",
" 1 | \n",
" 0 | \n",
" NaN | \n",
" NaN | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" gas Sweden | \n",
" bus Sweden | \n",
" PQ | \n",
" | \n",
" 50.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 1.0 | \n",
" ... | \n",
" 0 | \n",
" 0 | \n",
" 1 | \n",
" 0 | \n",
" NaN | \n",
" NaN | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" gas Norway | \n",
" bus Norway | \n",
" PQ | \n",
" | \n",
" 50.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 1.0 | \n",
" ... | \n",
" 0 | \n",
" 0 | \n",
" 1 | \n",
" 0 | \n",
" NaN | \n",
" NaN | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" wind Denmark | \n",
" bus Denmark | \n",
" PQ | \n",
" | \n",
" 200.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 1.0 | \n",
" ... | \n",
" 0 | \n",
" 0 | \n",
" 1 | \n",
" 0 | \n",
" NaN | \n",
" NaN | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
4 rows × 37 columns
\n",
"
"
],
"text/plain": [
" bus control type p_nom p_nom_mod p_nom_extendable \\\n",
"Generator \n",
"gas Denmark bus Denmark PQ 50.0 0.0 False \n",
"gas Sweden bus Sweden PQ 50.0 0.0 False \n",
"gas Norway bus Norway PQ 50.0 0.0 False \n",
"wind Denmark bus Denmark PQ 200.0 0.0 False \n",
"\n",
" p_nom_min p_nom_max p_min_pu p_max_pu ... min_up_time \\\n",
"Generator ... \n",
"gas Denmark 0.0 inf 0.0 1.0 ... 0 \n",
"gas Sweden 0.0 inf 0.0 1.0 ... 0 \n",
"gas Norway 0.0 inf 0.0 1.0 ... 0 \n",
"wind Denmark 0.0 inf 0.0 1.0 ... 0 \n",
"\n",
" min_down_time up_time_before down_time_before ramp_limit_up \\\n",
"Generator \n",
"gas Denmark 0 1 0 NaN \n",
"gas Sweden 0 1 0 NaN \n",
"gas Norway 0 1 0 NaN \n",
"wind Denmark 0 1 0 NaN \n",
"\n",
" ramp_limit_down ramp_limit_start_up ramp_limit_shut_down \\\n",
"Generator \n",
"gas Denmark NaN 1.0 1.0 \n",
"gas Sweden NaN 1.0 1.0 \n",
"gas Norway NaN 1.0 1.0 \n",
"wind Denmark NaN 1.0 1.0 \n",
"\n",
" weight p_nom_opt \n",
"Generator \n",
"gas Denmark 1.0 0.0 \n",
"gas Sweden 1.0 0.0 \n",
"gas Norway 1.0 0.0 \n",
"wind Denmark 1.0 0.0 \n",
"\n",
"[4 rows x 37 columns]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for node in [\"Denmark\", \"Sweden\", \"Norway\"]:\n",
" network.add(\"Generator\", \"gas {}\".format(node), bus=\"bus {}\".format(node), \n",
" p_nom=50, \n",
" marginal_cost=50) #EUR/MWh_elec \n",
"network.add(\"Generator\", \n",
" \"wind Denmark\", \n",
" bus=\"bus Denmark\", \n",
" p_nom=200, \n",
" marginal_cost=10)\n",
"network.generators"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We add the loads."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" bus | \n",
" carrier | \n",
" type | \n",
" p_set | \n",
" q_set | \n",
" sign | \n",
" active | \n",
"
\n",
" \n",
" Load | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" load Denmark | \n",
" bus Denmark | \n",
" | \n",
" | \n",
" 50.0 | \n",
" 0.0 | \n",
" -1.0 | \n",
" True | \n",
"
\n",
" \n",
" load Sweden | \n",
" bus Sweden | \n",
" | \n",
" | \n",
" 50.0 | \n",
" 0.0 | \n",
" -1.0 | \n",
" True | \n",
"
\n",
" \n",
" load Norway | \n",
" bus Norway | \n",
" | \n",
" | \n",
" 30.0 | \n",
" 0.0 | \n",
" -1.0 | \n",
" True | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" bus carrier type p_set q_set sign active\n",
"Load \n",
"load Denmark bus Denmark 50.0 0.0 -1.0 True\n",
"load Sweden bus Sweden 50.0 0.0 -1.0 True\n",
"load Norway bus Norway 30.0 0.0 -1.0 True"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"for node in [\"Denmark\", \"Sweden\"]:\n",
" network.add(\"Load\", \"load {}\".format(node), \n",
" bus=\"bus {}\".format(node), \n",
" p_set=50)\n",
"network.add(\"Load\", \"load Norway\", \n",
" bus=\"bus Norway\", \n",
" p_set=30)\n",
"network.loads"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We optimize searching for the minimum system cost."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:pypsa.consistency:The following lines have carriers which are not defined:\n",
"Index(['line DK-SW', 'line DK-NO', 'line SW-NO'], dtype='object', name='Line')\n",
"WARNING:pypsa.consistency:The following buses have carriers which are not defined:\n",
"Index(['bus Denmark', 'bus Sweden', 'bus Norway'], dtype='object', name='Bus')\n",
"WARNING:pypsa.consistency:The following lines have carriers which are not defined:\n",
"Index(['line DK-SW', 'line DK-NO', 'line SW-NO'], dtype='object', name='Line')\n",
"WARNING:pypsa.consistency:The following buses have carriers which are not defined:\n",
"Index(['bus Denmark', 'bus Sweden', 'bus Norway'], dtype='object', name='Bus')\n",
"INFO:linopy.model: Solve problem using Highs solver\n",
"INFO:linopy.io: Writing time: 0.02s\n",
"INFO:linopy.constants: Optimization successful: \n",
"Status: ok\n",
"Termination condition: optimal\n",
"Solution: 7 primals, 18 duals\n",
"Objective: 1.30e+03\n",
"Solver model: available\n",
"Solver message: optimal\n",
"\n",
"INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper, Line-fix-s-lower, Line-fix-s-upper, Kirchhoff-Voltage-Law were not assigned to the network.\n"
]
},
{
"data": {
"text/plain": [
"('ok', 'optimal')"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.optimize()\n",
"#network.optimize(solver='gurobi', assign_all_duals=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we can look at what is the optimal dispatch form every genenerator. As expected, the wind generator is producing power to supply the demand in every node."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Generator | \n",
" gas Denmark | \n",
" gas Sweden | \n",
" gas Norway | \n",
" wind Denmark | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" -0.0 | \n",
" -0.0 | \n",
" -0.0 | \n",
" 130.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Generator gas Denmark gas Sweden gas Norway wind Denmark\n",
"snapshot \n",
"now -0.0 -0.0 -0.0 130.0"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.generators_t.p"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can see the optimal dispatch in the generators and then solve the non-linear power flow using a Newton-Raphson method."
]
},
{
"cell_type": "code",
"execution_count": 9,
"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 7.362638e-09,\n",
" 'converged': SubNetwork 0\n",
" snapshot \n",
" now True}"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.generators_t.p_set = network.generators_t.p\n",
"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": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" line DK-SW | \n",
" line DK-NO | \n",
" line SW-NO | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 43.333338 | \n",
" 36.66667 | \n",
" -6.666667 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" line DK-SW line DK-NO line SW-NO\n",
"snapshot \n",
"now 43.333338 36.66667 -6.666667"
]
},
"execution_count": 10,
"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"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Bus | \n",
" bus Denmark | \n",
" bus Sweden | \n",
" bus Norway | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 0.0 | \n",
" -0.000062 | \n",
" -0.000053 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Bus bus Denmark bus Sweden bus Norway\n",
"snapshot \n",
"now 0.0 -0.000062 -0.000053"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.buses_t.v_ang * 180 / np.pi"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and their per-unit mangitudes"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Bus | \n",
" bus Denmark | \n",
" bus Sweden | \n",
" bus Norway | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 1.0 | \n",
" 1.0 | \n",
" 1.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Bus bus Denmark bus Sweden bus Norway\n",
"snapshot \n",
"now 1.0 1.0 1.0"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.buses_t.v_mag_pu"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**b) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the power flows along the transmission lines using a linearized approximation (also known as DC optimal power flow)**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case, since the voltage angles are very small, the linear power flow should be a good approximation. We can calculate the power flows in the line using the linear power flow (lpf) and check that we obtained a very similar result."
]
},
{
"cell_type": "code",
"execution_count": 13,
"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": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" line DK-SW | \n",
" line DK-NO | \n",
" line SW-NO | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 43.333333 | \n",
" 36.666667 | \n",
" -6.666667 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" line DK-SW line DK-NO line SW-NO\n",
"snapshot \n",
"now 43.333333 36.666667 -6.666667"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.lines_t.p0"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**c) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the power flows along the transmission lines using Net Transfer Capacity (NTC) approach for the transmission lines and discuss the results.**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can create the problem again and this time use links to represent lines using only their Net Transfer Capacities. \n",
"By selecting p_min_pu=-1 we make the link reversible."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:pypsa.consistency:The following links have carriers which are not defined:\n",
"Index(['line DK-SW', 'line DK-NO', 'line SW-NO'], dtype='object', name='Link')\n",
"WARNING:pypsa.consistency:The following buses have carriers which are not defined:\n",
"Index(['bus Denmark', 'bus Sweden', 'bus Norway'], dtype='object', name='Bus')\n",
"WARNING:pypsa.consistency:The following links have carriers which are not defined:\n",
"Index(['line DK-SW', 'line DK-NO', 'line SW-NO'], dtype='object', name='Link')\n",
"WARNING:pypsa.consistency:The following buses have carriers which are not defined:\n",
"Index(['bus Denmark', 'bus Sweden', 'bus Norway'], dtype='object', name='Bus')\n",
"INFO:linopy.model: Solve problem using Highs solver\n",
"INFO:linopy.io: Writing time: 0.03s\n",
"INFO:linopy.constants: Optimization successful: \n",
"Status: ok\n",
"Termination condition: optimal\n",
"Solution: 7 primals, 17 duals\n",
"Objective: 1.30e+03\n",
"Solver model: available\n",
"Solver message: optimal\n",
"\n",
"INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper, Link-fix-p-lower, Link-fix-p-upper were not assigned to the network.\n"
]
},
{
"data": {
"text/plain": [
"('ok', 'optimal')"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network = pypsa.Network()\n",
"for node in [\"Denmark\", \"Sweden\", \"Norway\"]:\n",
" network.add(\"Bus\", \"bus {}\".format(node), v_nom=2000)\n",
"\n",
"network.add(\"Link\",\"line DK-SW\", bus0 = \"bus Denmark\", bus1 = \"bus Sweden\", p_nom = 100, p_min_pu=-1)\n",
"network.add(\"Link\",\"line DK-NO\", bus0 = \"bus Denmark\", bus1 = \"bus Norway\", p_nom =100, p_min_pu=-1)\n",
"network.add(\"Link\",\"line SW-NO\", bus0 = \"bus Sweden\", bus1 = \"bus Norway\", p_nom = 100, p_min_pu=-1)\n",
"\n",
"for node in [\"Denmark\", \"Sweden\"]:\n",
" network.add(\"Load\", \"load {}\".format(node), \n",
" bus=\"bus {}\".format(node), \n",
" p_set=50)\n",
"network.add(\"Load\", \"load Norway\", \n",
" bus=\"bus Norway\", \n",
" p_set=30)\n",
"network.loads\n",
"\n",
"for node in [\"Denmark\", \"Sweden\", \"Norway\"]:\n",
" network.add(\"Generator\", \"gas {}\".format(node), bus=\"bus {}\".format(node), \n",
" p_nom=50, \n",
" marginal_cost=50) #EUR/MWh_elec \n",
"network.add(\"Generator\", \"wind Denmark\", bus=\"bus Denmark\", \n",
" p_nom=200, \n",
" marginal_cost=10)\n",
"\n",
"\n",
"network.optimize()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Generator | \n",
" gas Denmark | \n",
" gas Sweden | \n",
" gas Norway | \n",
" wind Denmark | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" -0.0 | \n",
" -0.0 | \n",
" -0.0 | \n",
" 130.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Generator gas Denmark gas Sweden gas Norway wind Denmark\n",
"snapshot \n",
"now -0.0 -0.0 -0.0 130.0"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.generators_t.p"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Link | \n",
" line DK-SW | \n",
" line DK-NO | \n",
" line SW-NO | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 100.0 | \n",
" -20.0 | \n",
" 50.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Link line DK-SW line DK-NO line SW-NO\n",
"snapshot \n",
"now 100.0 -20.0 50.0"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.links_t.p0"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case, the power flows are also compatible with the nodal balances, but they are significantly different from those obtained using AC power flow or linearized AC power flow to represent the power flowing through the different lines."
]
},
{
"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
}