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
[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.23.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.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')
<__array_function__ internals>:200: RuntimeWarning: invalid value encountered in cast
<__array_function__ internals>:200: RuntimeWarning: invalid value encountered in cast
<__array_function__ internals>:200: RuntimeWarning: invalid value encountered in cast
<__array_function__ internals>:200: RuntimeWarning: invalid value encountered in cast
INFO:linopy.model: Solve linear problem using Glpk solver
INFO:linopy.io: Writing time: 0.19s
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
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
--lp /tmp/linopy-problem-tb5u0w98.lp --output /tmp/linopy-solve-7rmpkau5.sol
Reading problem data from '/tmp/linopy-problem-tb5u0w98.lp'...
492 rows, 199 columns, 1053 non-zeros
3319 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-7rmpkau5.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.