{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Problem 5.3 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Integrated Energy Grids**\n",
"\n",
"**Problem 5.3**\n",
"\n",
"_Note: This is equivalent to Problem 2.2 which we solved using linopy, but here we will use PyPSA._\n",
"\n",
"**Consider the following economic dispatch problem:**\n",
"\n",
"**• we have three generators: solar, wind and gas**\n",
"\n",
"**• solar and wind have no marginal costs, and gas has fuel costs of 60 EUR/MWh.**\n",
"\n",
"**• we need to cover a electricity demand of 13.2 MWh**\n",
"\n",
"**• the installed capacities are 15 MW, 20 MW and 20 MW for wind, solar, and gas, respectively**\n",
"\n",
"**• assume the capacity factor for solar is 0.17 and for wind 0.33.**\n",
"\n",
"**Use PYPSA to find the optimal solution as well and obtain the electricity price (Lagrange multiplier for the energy balance constraint)**\n",
"\n"
]
},
{
"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": 6,
"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 bus."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"network = pypsa.Network()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"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",
" my bus | \n",
" 1.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",
"my bus 1.0 0.0 0.0 AC 1.0 0.0 \n",
"\n",
" v_mag_pu_max control generator sub_network \n",
"Bus \n",
"my bus inf PQ "
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.add(\"Bus\", \"my bus\") \n",
"network.buses"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We add the generators"
]
},
{
"cell_type": "code",
"execution_count": 9,
"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",
" solar | \n",
" my bus | \n",
" PQ | \n",
" | \n",
" 15.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 0.17 | \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 | \n",
" my bus | \n",
" PQ | \n",
" | \n",
" 20.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 0.33 | \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 | \n",
" my bus | \n",
" PQ | \n",
" | \n",
" 20.0 | \n",
" 0.0 | \n",
" False | \n",
" 0.0 | \n",
" inf | \n",
" 0.0 | \n",
" 1.00 | \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",
"
3 rows × 37 columns
\n",
"
"
],
"text/plain": [
" bus control type p_nom p_nom_mod p_nom_extendable p_nom_min \\\n",
"Generator \n",
"solar my bus PQ 15.0 0.0 False 0.0 \n",
"wind my bus PQ 20.0 0.0 False 0.0 \n",
"gas my bus PQ 20.0 0.0 False 0.0 \n",
"\n",
" p_nom_max p_min_pu p_max_pu ... min_up_time min_down_time \\\n",
"Generator ... \n",
"solar inf 0.0 0.17 ... 0 0 \n",
"wind inf 0.0 0.33 ... 0 0 \n",
"gas inf 0.0 1.00 ... 0 0 \n",
"\n",
" up_time_before down_time_before ramp_limit_up ramp_limit_down \\\n",
"Generator \n",
"solar 1 0 NaN NaN \n",
"wind 1 0 NaN NaN \n",
"gas 1 0 NaN NaN \n",
"\n",
" ramp_limit_start_up ramp_limit_shut_down weight p_nom_opt \n",
"Generator \n",
"solar 1.0 1.0 1.0 0.0 \n",
"wind 1.0 1.0 1.0 0.0 \n",
"gas 1.0 1.0 1.0 0.0 \n",
"\n",
"[3 rows x 37 columns]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.add(\"Generator\", \n",
" \"solar\", \n",
" bus=\"my bus\", \n",
" p_nom=15, \n",
" p_max_pu=0.17, #capacity factor\n",
" marginal_cost=0) \n",
" \n",
"network.add(\"Generator\", \n",
" \"wind\", \n",
" bus=\"my bus\", \n",
" p_nom=20, \n",
" p_max_pu=0.33, #capacity factor\n",
" marginal_cost=0) \n",
"\n",
"network.add(\"Generator\", \n",
" \"gas\", \n",
" bus=\"my bus\", \n",
" p_nom=20, \n",
" marginal_cost=60) #EUR/MWh_elec\n",
"network.generators"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We add the load"
]
},
{
"cell_type": "code",
"execution_count": 10,
"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",
" electricity demand | \n",
" my bus | \n",
" | \n",
" | \n",
" 13.2 | \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",
"electricity demand my bus 13.2 0.0 -1.0 True"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.add(\"Load\", \n",
" \"electricity demand\", \n",
" bus=\"my bus\", \n",
" p_set=13.2)\n",
"network.loads"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Calculate the optimal economic dispatch"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:pypsa.consistency:The following buses have carriers which are not defined:\n",
"Index(['my bus'], dtype='object', name='Bus')\n",
"WARNING:pypsa.consistency:The following buses have carriers which are not defined:\n",
"Index(['my bus'], 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: 3 primals, 7 duals\n",
"Objective: 2.43e+02\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 were not assigned to the network.\n"
]
},
{
"data": {
"text/plain": [
"('ok', 'optimal')"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.optimize()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can show the optimal dispatch and the electricity price (marginal cost at the bus)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Generator | \n",
" solar | \n",
" wind | \n",
" gas | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 2.55 | \n",
" 6.6 | \n",
" 4.05 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Generator solar wind gas\n",
"snapshot \n",
"now 2.55 6.6 4.05"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.generators_t.p"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" Bus | \n",
" my bus | \n",
"
\n",
" \n",
" snapshot | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" now | \n",
" 60.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
"Bus my bus\n",
"snapshot \n",
"now 60.0"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"network.buses_t.marginal_price"
]
},
{
"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
}