Constraining the total capacity per bus and carrier

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.31.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 links have carriers which are not defined:
Index(['Norwich Converter', 'Norway Converter', 'Bremen Converter', 'DC link'], dtype='object', name='Link')
WARNING:pypsa.consistency:The following lines have carriers which are not defined:
Index(['0', '1', '2', '3', '4', '5', '6'], dtype='object', name='Line')
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')
WARNING:pypsa.consistency:The following buses have carriers which are not defined:
Index(['London', 'Norwich', 'Norwich DC', 'Manchester', 'Bremen', 'Bremen DC',
       'Frankfurt', 'Norway', 'Norway DC'],
      dtype='object', name='Bus')
WARNING:pypsa.consistency:The following links have carriers which are not defined:
Index(['Norwich Converter', 'Norway Converter', 'Bremen Converter', 'DC link'], dtype='object', name='Link')
WARNING:pypsa.consistency:The following lines have carriers which are not defined:
Index(['0', '1', '2', '3', '4', '5', '6'], dtype='object', name='Line')
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')
WARNING:pypsa.consistency:The following buses have carriers which are not defined:
Index(['London', 'Norwich', 'Norwich DC', 'Manchester', 'Bremen', 'Bremen DC',
       'Frankfurt', 'Norway', 'Norway DC'],
      dtype='object', name='Bus')
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/envs/v0.31.0/lib/python3.12/site-packages/linopy/common.py:147: UserWarning: coords for dimension(s) ['Generator'] is not aligned with the pandas object. Previously, the indexes of the pandas were ignored and overwritten in these cases. Now, the pandas object's coordinates are taken considered for alignment.
  warn(
INFO:linopy.model: Solve problem using Highs solver
INFO:linopy.io: Writing time: 0.09s
INFO:linopy.solvers:Log file at /tmp/highs.log
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 199 primals, 499 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.7.2 (git hash: 184e327): Copyright (c) 2024 HiGHS under MIT licence terms
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
318 rows, 114 cols, 1061 nonzeros  0s
Presolve : Reductions: rows 318(-181); columns 114(-85); elements 1061(-62)
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   status      : Optimal
Simplex   iterations: 121
Objective value     : -1.3793078250e+07
HiGHS run time      :          0.00
Writing the solution to /tmp/linopy-solve-bheuu4ft.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.