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 pandas as pd
import pypsa
[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.34.0. 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.consistency:The following lines have zero x, which could break the linear load flow:
Index(['2', '3', '4'], dtype='object', name='Line')
WARNING:pypsa.consistency: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 Highs solver
INFO:linopy.io: Writing time: 0.06s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 199 primals, 492 duals
Objective: -1.38e+07
Solver model: 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.
Running HiGHS 1.10.0 (git hash: fd86653): Copyright (c) 2025 HiGHS under MIT licence terms
LP linopy-problem-plgc5pmx has 492 rows; 199 cols; 1053 nonzeros
Coefficient ranges:
Matrix [1e-02, 1e+00]
Cost [9e-03, 3e+03]
Bound [2e+07, 2e+07]
RHS [9e-01, 2e+03]
Presolving model
403 rows, 198 cols, 964 nonzeros 0s
320 rows, 115 cols, 1055 nonzeros 0s
Dependent equations search running on 26 equations with time limit of 1000.00s
Dependent equations search removed 0 rows and 0 nonzeros in 0.00s (limit = 1000.00s)
318 rows, 114 cols, 1061 nonzeros 0s
Presolve : Reductions: rows 318(-174); columns 114(-85); elements 1061(+8)
Solving the presolved LP
Using EKK dual simplex solver - serial
Iteration Objective Infeasibilities num(sum)
0 -1.5896394920e+07 Pr: 101(185533); Du: 0(3.84552e-11) 0s
121 -1.3793078250e+07 Pr: 0(0) 0s
Solving the original LP from the solution after postsolve
Model name : linopy-problem-plgc5pmx
Model status : Optimal
Simplex iterations: 121
Objective value : -1.3793078250e+07
Relative P-D gap : 2.7008404005e-16
HiGHS run time : 0.00
Writing the solution to /tmp/linopy-solve-7skukscw.sol
[4]:
('ok', 'optimal')
[5]:
n.generators[["p_nom_opt"]]
[5]:
| p_nom_opt | |
|---|---|
| Generator | |
| Manchester Wind | 2000.000000 |
| Manchester Gas | -0.000000 |
| Norway Wind | 895.372552 |
| Norway Gas | 91.001539 |
| Frankfurt Wind | 100.000000 |
| Frankfurt Gas | 884.092697 |
| Frankfurt Wind 2 | 2100.000000 |
Looks good! The generators of carrier ‘wind’ at bus ‘Frankfurt’ are just the limit of 2200 MW.