Problem 6.2

Problem 6.2#

Integrated Energy Grids

Problem 6.2

Assume we have one bus (Denmark) in which there is a gas power generator whose variable cost is 50 EUR/MWh and installed capacity is 50 MW, and a wind generator whose variable cost is zero and whose installed capacity is 30 MW. Using Python for Power System Analysis (PyPSA):

a) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the electricity price assuming that power demand is 80 MW

b) Calculate the optimal dispatch that minimizes the total system cost, the energy produced by each generator, and the electricity price assuming that power demand is 20 MW

Note: This is a straightforward problem, whose objective is to showcase how to solve one-node economic dispatch problems in PyPSA. It is recommended to follow the PyPSA tutorial before trying this problem.

Note

If you have not yet set up Python on your computer, you can execute this tutorial in your browser via Google Colab. 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.

Then install the following packages by executing the following command in a Jupyter cell at the top of the notebook.

!pip install numpy pypsa
import numpy as np
import pypsa
Set parameter Username
Set parameter LicenseID to value 2767832
Academic license - for non-commercial use only - expires 2027-01-20

We start by creating the network object and adding the bus.

network = pypsa.Network()
network.add("Bus", 
            "bus Denmark") 
network.buses
v_nom type x y carrier unit location v_mag_pu_set v_mag_pu_min v_mag_pu_max control generator sub_network
name
bus Denmark 1.0 0.0 0.0 AC 1.0 0.0 inf PQ

We add the generators

network.add("Generator", 
            "gas Denmark", 
            bus="bus Denmark", 
            p_nom=50, 
            marginal_cost=50) #EUR/MWh_elec
    
network.add("Generator", 
            "wind Denmark", 
            bus="bus Denmark", 
            p_nom=30, 
            marginal_cost=0)
network.generators
bus control type p_nom p_nom_mod p_nom_extendable p_nom_min p_nom_max p_nom_set p_min_pu ... min_up_time min_down_time up_time_before down_time_before ramp_limit_up ramp_limit_down ramp_limit_start_up ramp_limit_shut_down weight p_nom_opt
name
gas Denmark bus Denmark PQ 50.0 0.0 False 0.0 inf NaN 0.0 ... 0 0 1 0 NaN NaN 1.0 1.0 1.0 0.0
wind Denmark bus Denmark PQ 30.0 0.0 False 0.0 inf NaN 0.0 ... 0 0 1 0 NaN NaN 1.0 1.0 1.0 0.0

2 rows × 38 columns

We add the load

network.add("Load", 
            "load Demmark", 
            bus="bus Denmark", 
            p_set=80)
network.loads
bus carrier type p_set q_set sign active
name
load Demmark bus Denmark 80.0 0.0 -1.0 True

Calculate the optimal economic dispatch

network.optimize()
WARNING:pypsa.consistency:The following buses have carriers which are not defined:
Index(['bus Denmark'], dtype='object', name='name')
INFO:linopy.model: Solve problem using Highs solver
INFO:linopy.io: Writing time: 0.13s
INFO:linopy.constants: Optimization successful: 
Status: ok
Termination condition: optimal
Solution: 2 primals, 5 duals
Objective: 2.50e+03
Solver model: available
Solver message: Optimal

INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper were not assigned to the network.
Running HiGHS 1.12.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
LP linopy-problem-ngyjvg0o has 5 rows; 2 cols; 6 nonzeros
Coefficient ranges:
  Matrix  [1e+00, 1e+00]
  Cost    [5e+01, 5e+01]
  Bound   [0e+00, 0e+00]
  RHS     [3e+01, 8e+01]
Presolving model
0 rows, 0 cols, 0 nonzeros  0s
0 rows, 0 cols, 0 nonzeros  0s
Presolve reductions: rows 0(-5); columns 0(-2); nonzeros 0(-6) - Reduced to empty
Performed postsolve
Solving the original LP from the solution after postsolve

Model name          : linopy-problem-ngyjvg0o
Model status        : Optimal
Objective value     :  2.5000000000e+03
P-D objective error :  0.0000000000e+00
HiGHS run time      :          0.00
('ok', 'optimal')

Now we can show the optimal dispatch and the electricity price (marginal cost at the bus)

network.generators_t.p
name gas Denmark wind Denmark
snapshot
now 50.0 30.0
network.buses_t.marginal_price
name bus Denmark
snapshot
now 50.0

We update the load and calculate the economic dispatch again.

network.add("Load", 
            "load Demmark", 
            bus="bus Denmark", 
            p_set=20, 
            overwrite=True)
network.optimize()
WARNING:pypsa.consistency:The following buses have carriers which are not defined:
Index(['bus Denmark'], dtype='object', name='name')
WARNING:pypsa.consistency:The following sub_networks have carriers which are not defined:
Index(['0'], dtype='object', name='name')
INFO:linopy.model: Solve problem using Highs solver
INFO:linopy.io: Writing time: 0.22s
INFO:linopy.constants: Optimization successful: 
Status: ok
Termination condition: optimal
Solution: 2 primals, 5 duals
Objective: 0.00e+00
Solver model: available
Solver message: Optimal

INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper were not assigned to the network.
Running HiGHS 1.12.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
LP linopy-problem-hsm7uzam has 5 rows; 2 cols; 6 nonzeros
Coefficient ranges:
  Matrix  [1e+00, 1e+00]
  Cost    [5e+01, 5e+01]
  Bound   [0e+00, 0e+00]
  RHS     [2e+01, 5e+01]
Presolving model
0 rows, 0 cols, 0 nonzeros  0s
0 rows, 0 cols, 0 nonzeros  0s
Presolve reductions: rows 0(-5); columns 0(-2); nonzeros 0(-6) - Reduced to empty
Performed postsolve
Solving the original LP from the solution after postsolve

Model name          : linopy-problem-hsm7uzam
Model status        : Optimal
Objective value     :  0.0000000000e+00
P-D objective error :  0.0000000000e+00
HiGHS run time      :          0.00
('ok', 'optimal')
network.generators_t.p
name gas Denmark wind Denmark
snapshot
now -0.0 20.0
network.buses_t.marginal_price
name bus Denmark
snapshot
now -0.0