Note

You can download this example as a Jupyter notebook or start it in interactive mode.

Constraining the total capacity per bus and carrier#

In this small example, we limit the nominal capacity of generators of the same production carrier at the same bus.

Therefore, we introduce a column nom_min_{carrier} and nom_max_{carrier} in the buses dataframe. These are then used as lower and upper bounds of generators of the same carrier at the same bus.

We start with importing a small example network.

[1]:
import pypsa
import pandas as pd
ERROR 1: PROJ: proj_create_from_database: Open of /home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/latest/share/proj failed
[2]:
n = pypsa.examples.ac_dc_meshed(from_master=True)
n.links_t.p_set = pd.DataFrame(
    index=n.snapshots
)  # remove forced fixed values in optimization
WARNING:pypsa.io:Importing network from PyPSA version v0.17.1 while current version is v0.25.2. Read the release notes at https://pypsa.readthedocs.io/en/latest/release_notes.html to prepare your network for import.
INFO:pypsa.io:Imported network ac-dc-meshed.nc has buses, carriers, generators, global_constraints, lines, links, loads

Now add a second wind generator at bus ‘Frankfurt’ and limit the combined capacity.

[3]:
n.add(
    "Generator",
    "Frankfurt Wind 2",
    bus="Frankfurt",
    capital_cost=120,
    carrier="wind",
    p_nom_extendable=True,
)

n.buses.loc[["Frankfurt", "Manchester"], "nom_min_wind"] = 2000
n.buses.loc[["Frankfurt"], "nom_max_wind"] = 2200

We are running the lopf and check whether the constraint is fulfilled.

[4]:
n.optimize()
WARNING:pypsa.components:The following lines have zero x, which could break the linear load flow:
Index(['2', '3', '4'], dtype='object', name='Line')
WARNING:pypsa.components:The following lines have zero r, which could break the linear load flow:
Index(['0', '1', '5', '6'], dtype='object', name='Line')
WARNING:pypsa.components:The following lines have zero x, which could break the linear load flow:
Index(['2', '3', '4'], dtype='object', name='Line')
WARNING:pypsa.components:The following lines have zero r, which could break the linear load flow:
Index(['0', '1', '5', '6'], dtype='object', name='Line')
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.16s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 199 primals, 492 duals
Objective: -1.38e+07
Solver model: not available
Solver message: optimal

INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-ext-p-lower, Generator-ext-p-upper, Line-ext-s-lower, Line-ext-s-upper, Link-ext-p-lower, Link-ext-p-upper, Kirchhoff-Voltage-Law were not assigned to the network.
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-swsfrdpt.lp --output /tmp/linopy-solve-b6_flirw.sol
Reading problem data from '/tmp/linopy-problem-swsfrdpt.lp'...
492 rows, 199 columns, 1053 non-zeros
2806 lines were read
GLPK Simplex Optimizer 5.0
492 rows, 199 columns, 1053 non-zeros
Preprocessing...
403 rows, 198 columns, 964 non-zeros
Scaling...
 A: min|aij| =  9.693e-03  max|aij| =  1.215e+00  ratio =  1.254e+02
GM: min|aij| =  5.786e-01  max|aij| =  1.728e+00  ratio =  2.987e+00
EQ: min|aij| =  3.377e-01  max|aij| =  1.000e+00  ratio =  2.961e+00
Constructing initial basis...
Size of triangular part is 403
      0: obj =  -1.578758761e+07 inf =   7.934e+04 (102)
    164: obj =  -1.007787982e+07 inf =   1.126e-12 (0) 1
*   244: obj =  -1.379307825e+07 inf =   9.329e-13 (0) 1
OPTIMAL LP SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.6 Mb (680925 bytes)
Writing basic solution to '/tmp/linopy-solve-b6_flirw.sol'...
[4]:
('ok', 'optimal')
[5]:
n.generators[["p_nom_opt"]]
[5]:
p_nom_opt
Generator
Manchester Wind 2000.0000
Manchester Gas 0.0000
Norway Wind 895.3730
Norway Gas 91.0015
Frankfurt Wind 100.0000
Frankfurt Gas 884.0930
Frankfurt Wind 2 2100.0000

Looks good! The generators of carrier ‘wind’ at bus ‘Frankfurt’ are just the limit of 2200 MW.