Note

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

Unit commitment#

This tutorial runs through examples of unit commitment for generators at a single bus. Examples of minimum part-load, minimum up time, minimum down time, start up costs, shut down costs and ramp rate restrictions are shown.

To enable unit commitment on a generator, set its attribute committable = True.

[1]:
import pypsa
import pandas as pd

Minimum part load demonstration#

In final hour load goes below part-load limit of coal gen (30%), forcing gas to commit.

[2]:
nu = pypsa.Network(snapshots=range(4))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    committable=True,
    p_min_pu=0.3,
    marginal_cost=20,
    p_nom=10000,
)

nu.add(
    "Generator",
    "gas",
    bus="bus",
    committable=True,
    marginal_cost=70,
    p_min_pu=0.1,
    p_nom=1000,
)

nu.add("Load", "load", bus="bus", p_set=[4000, 6000, 5000, 800])
[3]:
nu.optimize()
<__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.07s
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 32 primals, 0 duals
Objective: 3.56e+05
Solver model: not available
Solver message: integer optimal

GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-ny90e_8b.lp --output /tmp/linopy-solve-wckb_5e8.sol
Reading problem data from '/tmp/linopy-problem-ny90e_8b.lp'...
36 rows, 32 columns, 84 non-zeros
24 integer variables, all of which are binary
288 lines were read
GLPK Integer Optimizer 5.0
36 rows, 32 columns, 84 non-zeros
24 integer variables, all of which are binary
Preprocessing...
2 hidden packing inequaliti(es) were detected
18 rows, 15 columns, 37 non-zeros
9 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 18
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
18 rows, 15 columns, 37 non-zeros
      0: obj =   5.060000000e+05 inf =   7.888e+01 (5)
      5: obj =   5.060000000e+05 inf =   0.000e+00 (0)
*    11: obj =   3.560000000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    11: mip =     not found yet >=              -inf        (1; 0)
+    11: >>>>>   3.560000000e+05 >=   3.560000000e+05   0.0% (1; 0)
+    11: mip =   3.560000000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (78551 bytes)
Writing MIP solution to '/tmp/linopy-solve-wckb_5e8.sol'...
[3]:
('ok', 'optimal')
[4]:
nu.generators_t.status
[4]:
Generator-com coal gas
snapshot
0 1.0 0.0
1 1.0 0.0
2 1.0 0.0
3 0.0 1.0
[5]:
nu.generators_t.p
[5]:
Generator coal gas
snapshot
0 4000.0 0.0
1 6000.0 0.0
2 5000.0 0.0
3 0.0 800.0

Minimum up time demonstration#

Gas has minimum up time, forcing it to be online longer

[6]:
nu = pypsa.Network(snapshots=range(4))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    committable=True,
    p_min_pu=0.3,
    marginal_cost=20,
    p_nom=10000,
)

nu.add(
    "Generator",
    "gas",
    bus="bus",
    committable=True,
    marginal_cost=70,
    p_min_pu=0.1,
    up_time_before=0,
    min_up_time=3,
    p_nom=1000,
)

nu.add("Load", "load", bus="bus", p_set=[4000, 800, 5000, 3000])
[7]:
nu.optimize()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
<__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.11s
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 32 primals, 0 duals
Objective: 3.06e+05
Solver model: not available
Solver message: integer optimal

GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-pyofcrsw.lp --output /tmp/linopy-solve-q_ib33nl.sol
Reading problem data from '/tmp/linopy-problem-pyofcrsw.lp'...
39 rows, 32 columns, 95 non-zeros
24 integer variables, all of which are binary
311 lines were read
GLPK Integer Optimizer 5.0
39 rows, 32 columns, 95 non-zeros
24 integer variables, all of which are binary
Preprocessing...
2 rows, 2 columns, 2 non-zeros
0 integer variables, none of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+00  ratio =  1.000e+00
Problem data seem to be well scaled
Constructing initial basis...
Size of triangular part is 2
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
2 rows, 2 columns, 2 non-zeros
*     0: obj =   3.960000000e+05 inf =   0.000e+00 (2)
*     2: obj =   3.060000000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+     2: mip =     not found yet >=              -inf        (1; 0)
+     2: >>>>>   3.060000000e+05 >=   3.060000000e+05   0.0% (1; 0)
+     2: mip =   3.060000000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (68056 bytes)
Writing MIP solution to '/tmp/linopy-solve-q_ib33nl.sol'...
[7]:
('ok', 'optimal')
[8]:
nu.generators_t.status
[8]:
Generator-com coal gas
snapshot
0 1.0 1.0
1 0.0 1.0
2 1.0 1.0
3 1.0 0.0
[9]:
nu.generators_t.p
[9]:
Generator coal gas
snapshot
0 3900.0 100.0
1 0.0 800.0
2 4900.0 100.0
3 3000.0 0.0

Minimum down time demonstration#

Coal has a minimum down time, forcing it to go off longer.

[10]:
nu = pypsa.Network(snapshots=range(4))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    committable=True,
    p_min_pu=0.3,
    marginal_cost=20,
    min_down_time=2,
    down_time_before=1,
    p_nom=10000,
)

nu.add(
    "Generator",
    "gas",
    bus="bus",
    committable=True,
    marginal_cost=70,
    p_min_pu=0.1,
    p_nom=4000,
)

nu.add("Load", "load", bus="bus", p_set=[3000, 800, 3000, 8000])
[11]:
nu.optimize()
WARNING:pypsa.components:The following committable generators were both up and down before the simulation: Index(['coal'], dtype='object', name='Generator'). This could cause an infeasibility.
WARNING:pypsa.components:The following committable generators were both up and down before the simulation: Index(['coal'], dtype='object', name='Generator'). This could cause an infeasibility.
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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.12s
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 32 primals, 0 duals
Objective: 4.86e+05
Solver model: not available
Solver message: integer optimal

GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-ozgdt744.lp --output /tmp/linopy-solve-ludtz42r.sol
Reading problem data from '/tmp/linopy-problem-ozgdt744.lp'...
40 rows, 32 columns, 94 non-zeros
24 integer variables, all of which are binary
314 lines were read
GLPK Integer Optimizer 5.0
40 rows, 32 columns, 94 non-zeros
24 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
1 constraint coefficient(s) were reduced
14 rows, 12 columns, 29 non-zeros
8 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  4.000e+03  ratio =  4.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 14
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
14 rows, 12 columns, 29 non-zeros
      0: obj =   8.360000000e+05 inf =   1.062e+02 (4)
      5: obj =   8.360000000e+05 inf =   0.000e+00 (0)
*    10: obj =   4.860000000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    10: mip =     not found yet >=              -inf        (1; 0)
+    10: >>>>>   4.860000000e+05 >=   4.860000000e+05   0.0% (1; 0)
+    10: mip =   4.860000000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (76022 bytes)
Writing MIP solution to '/tmp/linopy-solve-ludtz42r.sol'...
[11]:
('ok', 'optimal')
[12]:
nu.objective
[12]:
486000.0
[13]:
nu.generators_t.status
[13]:
Generator-com coal gas
snapshot
0 0.0 1.0
1 0.0 1.0
2 1.0 0.0
3 1.0 0.0
[14]:
nu.generators_t.p
[14]:
Generator coal gas
snapshot
0 0.0 3000.0
1 0.0 800.0
2 3000.0 0.0
3 8000.0 0.0

Start up and shut down costs#

Now there are associated costs for shutting down, etc

[15]:
nu = pypsa.Network(snapshots=range(4))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    committable=True,
    p_min_pu=0.3,
    marginal_cost=20,
    min_down_time=2,
    start_up_cost=5000,
    p_nom=10000,
)

nu.add(
    "Generator",
    "gas",
    bus="bus",
    committable=True,
    marginal_cost=70,
    p_min_pu=0.1,
    shut_down_cost=25,
    p_nom=4000,
)

nu.add("Load", "load", bus="bus", p_set=[3000, 800, 3000, 8000])
[16]:
nu.optimize()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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.11s
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 32 primals, 0 duals
Objective: 4.91e+05
Solver model: not available
Solver message: integer optimal

GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-vawilo6m.lp --output /tmp/linopy-solve-qzcmr83e.sol
Reading problem data from '/tmp/linopy-problem-vawilo6m.lp'...
39 rows, 32 columns, 93 non-zeros
24 integer variables, all of which are binary
325 lines were read
GLPK Integer Optimizer 5.0
39 rows, 32 columns, 93 non-zeros
24 integer variables, all of which are binary
Preprocessing...
7 hidden packing inequaliti(es) were detected
2 constraint coefficient(s) were reduced
25 rows, 20 columns, 51 non-zeros
14 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  4.000e+03  ratio =  4.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 25
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
25 rows, 20 columns, 51 non-zeros
      0: obj =   8.360000000e+05 inf =   1.579e+02 (8)
      9: obj =   8.410312500e+05 inf =   0.000e+00 (0)
*    25: obj =   4.910250000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    25: mip =     not found yet >=              -inf        (1; 0)
+    26: >>>>>   4.910250000e+05 >=   4.910250000e+05   0.0% (2; 0)
+    26: mip =   4.910250000e+05 >=     tree is empty   0.0% (0; 3)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (94710 bytes)
Writing MIP solution to '/tmp/linopy-solve-qzcmr83e.sol'...
[16]:
('ok', 'optimal')
[17]:
nu.objective
[17]:
491025.0
[18]:
nu.generators_t.status
[18]:
Generator-com coal gas
snapshot
0 0.0 1.0
1 0.0 1.0
2 1.0 0.0
3 1.0 0.0
[19]:
nu.generators_t.p
[19]:
Generator coal gas
snapshot
0 0.0 3000.0
1 0.0 800.0
2 3000.0 0.0
3 8000.0 0.0

Ramp rate limits#

[20]:
nu = pypsa.Network(snapshots=range(6))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    marginal_cost=20,
    ramp_limit_up=0.1,
    ramp_limit_down=0.2,
    p_nom=10000,
)

nu.add("Generator", "gas", bus="bus", marginal_cost=70, p_nom=4000)

nu.add("Load", "load", bus="bus", p_set=[4000, 7000, 7000, 7000, 7000, 3000])
[21]:
nu.optimize()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-fix-p-ramp_limit_up` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-fix-p-ramp_limit_down` to match existing coordinates.
  warnings.warn(
<__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.06s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 12 primals, 40 duals
Objective: 9.50e+05
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-7gm6swdt.lp --output /tmp/linopy-solve-i5k0wvrd.sol
Reading problem data from '/tmp/linopy-problem-7gm6swdt.lp'...
40 rows, 12 columns, 56 non-zeros
260 lines were read
GLPK Simplex Optimizer 5.0
40 rows, 12 columns, 56 non-zeros
Preprocessing...
8 rows, 6 columns, 16 non-zeros
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+00  ratio =  1.000e+00
Problem data seem to be well scaled
Constructing initial basis...
Size of triangular part is 8
      0: obj =   1.850000000e+06 inf =   3.000e+03 (2)
      2: obj =   1.700000000e+06 inf =   0.000e+00 (0)
*     9: obj =   9.500000000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.0 Mb (49911 bytes)
Writing basic solution to '/tmp/linopy-solve-i5k0wvrd.sol'...
[21]:
('ok', 'optimal')
[22]:
nu.generators_t.p
[22]:
Generator coal gas
snapshot
0 4000.0 0.0
1 5000.0 2000.0
2 6000.0 1000.0
3 7000.0 0.0
4 5000.0 2000.0
5 3000.0 0.0
[23]:
nu = pypsa.Network(snapshots=range(6))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    marginal_cost=20,
    ramp_limit_up=0.1,
    ramp_limit_down=0.2,
    p_nom_extendable=True,
    capital_cost=1e2,
)

nu.add("Generator", "gas", bus="bus", marginal_cost=70, p_nom=4000)

nu.add("Load", "load", bus="bus", p_set=[4000, 7000, 7000, 7000, 7000, 3000])
[24]:
nu.optimize()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-ext-p-ramp_limit_up` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-ext-p-ramp_limit_down` to match existing coordinates.
  warnings.warn(
<__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.1s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 13 primals, 41 duals
Objective: 1.68e+06
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-07gcukcd.lp --output /tmp/linopy-solve-5r1yljz6.sol
Reading problem data from '/tmp/linopy-problem-07gcukcd.lp'...
41 rows, 13 columns, 73 non-zeros
283 lines were read
GLPK Simplex Optimizer 5.0
41 rows, 13 columns, 73 non-zeros
Preprocessing...
15 rows, 7 columns, 39 non-zeros
Scaling...
 A: min|aij| =  1.000e-01  max|aij| =  1.000e+00  ratio =  1.000e+01
Problem data seem to be well scaled
Constructing initial basis...
Size of triangular part is 15
      0: obj =   1.850000000e+06 inf =   1.800e+04 (6)
      3: obj =   1.895000000e+06 inf =   0.000e+00 (0)
*    12: obj =   1.675000000e+06 inf =   6.821e-13 (0)
OPTIMAL LP SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (53519 bytes)
Writing basic solution to '/tmp/linopy-solve-5r1yljz6.sol'...
[24]:
('ok', 'optimal')
[25]:
nu.generators.p_nom_opt
[25]:
Generator
coal    5000.0
gas     4000.0
Name: p_nom_opt, dtype: float64
[26]:
nu.generators_t.p
[26]:
Generator coal gas
snapshot
0 4000.0 0.0
1 4500.0 2500.0
2 5000.0 2000.0
3 5000.0 2000.0
4 4000.0 3000.0
5 3000.0 0.0
[27]:
nu = pypsa.Network(snapshots=range(7))

nu.add("Bus", "bus")

# Can get bad interactions if SU > RU and p_min_pu; similarly if SD > RD
nu.add(
    "Generator",
    "coal",
    bus="bus",
    marginal_cost=20,
    committable=True,
    p_min_pu=0.05,
    initial_status=0,
    ramp_limit_start_up=0.1,
    ramp_limit_up=0.2,
    ramp_limit_down=0.25,
    ramp_limit_shut_down=0.15,
    p_nom=10000.0,
)

nu.add("Generator", "gas", bus="bus", marginal_cost=70, p_nom=10000)

nu.add("Load", "load", bus="bus", p_set=[0.0, 200.0, 7000, 7000, 7000, 2000, 0])
WARNING:pypsa.components:Generator has no attribute initial_status, ignoring this passed value.
[28]:
nu.optimize()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-fix-p-ramp_limit_up` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-fix-p-ramp_limit_down` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-p-ramp_limit_up` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-p-ramp_limit_down` to match existing coordinates.
  warnings.warn(
<__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.14s
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 35 primals, 0 duals
Objective: 1.15e+06
Solver model: not available
Solver message: integer optimal

GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-1i72457e.lp --output /tmp/linopy-solve-s7wocoha.sol
Reading problem data from '/tmp/linopy-problem-1i72457e.lp'...
61 rows, 35 columns, 144 non-zeros
21 integer variables, all of which are binary
457 lines were read
GLPK Integer Optimizer 5.0
61 rows, 35 columns, 144 non-zeros
21 integer variables, all of which are binary
Preprocessing...
2 hidden packing inequaliti(es) were detected
5 constraint coefficient(s) were reduced
24 rows, 16 columns, 66 non-zeros
12 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  5.000e+03  ratio =  5.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  2.441e-01  max|aij| =  1.465e+00  ratio =  6.000e+00
Constructing initial basis...
Size of triangular part is 24
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
24 rows, 16 columns, 66 non-zeros
*     0: obj =   1.624000000e+06 inf =   0.000e+00 (4)
*    16: obj =   1.149000000e+06 inf =   1.782e-14 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    16: mip =     not found yet >=              -inf        (1; 0)
+    16: >>>>>   1.149000000e+06 >=   1.149000000e+06   0.0% (1; 0)
+    16: mip =   1.149000000e+06 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (98846 bytes)
Writing MIP solution to '/tmp/linopy-solve-s7wocoha.sol'...
[28]:
('ok', 'optimal')
[29]:
nu.generators_t.p
[29]:
Generator coal gas
snapshot
0 0.0 0.0
1 0.0 200.0
2 1000.0 6000.0
3 3000.0 4000.0
4 4000.0 3000.0
5 1500.0 500.0
6 0.0 0.0
[30]:
nu.generators_t.status
[30]:
Generator-com coal
snapshot
0 0.0
1 0.0
2 1.0
3 1.0
4 1.0
5 1.0
6 0.0
[31]:
nu.generators.loc["coal"]
[31]:
attribute
bus                         bus
control                      PQ
type
p_nom                   10000.0
p_nom_extendable          False
p_nom_min                   0.0
p_nom_max                   inf
p_min_pu                   0.05
p_max_pu                    1.0
p_set                       0.0
q_set                       0.0
sign                        1.0
carrier
marginal_cost              20.0
build_year                    0
lifetime                    inf
capital_cost                0.0
efficiency                  1.0
committable                True
start_up_cost               0.0
shut_down_cost              0.0
min_up_time                   0
min_down_time                 0
up_time_before                1
down_time_before              0
ramp_limit_up               0.2
ramp_limit_down            0.25
ramp_limit_start_up         0.1
ramp_limit_shut_down       0.15
p_nom_opt               10000.0
Name: coal, dtype: object

Rolling horizon example#

This example solves sequentially in batches

[32]:
sets_of_snapshots = 6
p_set = [4000, 5000, 700, 800, 4000]

nu = pypsa.Network(snapshots=range(len(p_set) * sets_of_snapshots))

nu.add("Bus", "bus")

nu.add(
    "Generator",
    "coal",
    bus="bus",
    committable=True,
    p_min_pu=0.3,
    marginal_cost=20,
    min_down_time=2,
    min_up_time=3,
    up_time_before=1,
    ramp_limit_up=1,
    ramp_limit_down=1,
    ramp_limit_start_up=1,
    ramp_limit_shut_down=1,
    shut_down_cost=150,
    start_up_cost=200,
    p_nom=10000,
)

nu.add(
    "Generator",
    "gas",
    bus="bus",
    committable=True,
    marginal_cost=70,
    p_min_pu=0.1,
    up_time_before=2,
    min_up_time=3,
    shut_down_cost=20,
    start_up_cost=50,
    p_nom=1000,
)

nu.add("Load", "load", bus="bus", p_set=p_set * sets_of_snapshots)
[33]:
overlap = 2
for i in range(sets_of_snapshots):
    nu.optimize(nu.snapshots[i * len(p_set) : (i + 1) * len(p_set) + overlap])
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-fix-p-ramp_limit_up` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-fix-p-ramp_limit_down` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-p-ramp_limit_up` to match existing coordinates.
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-p-ramp_limit_down` to match existing coordinates.
  warnings.warn(
<__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
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 56 primals, 0 duals
Objective: 5.55e+05
Solver model: not available
Solver message: integer optimal

/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-cx5lrttl.lp --output /tmp/linopy-solve-w8td9sqt.sol
Reading problem data from '/tmp/linopy-problem-cx5lrttl.lp'...
108 rows, 56 columns, 277 non-zeros
42 integer variables, all of which are binary
827 lines were read
GLPK Integer Optimizer 5.0
108 rows, 56 columns, 277 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
23 rows, 20 columns, 58 non-zeros
15 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 23
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
23 rows, 20 columns, 58 non-zeros
      0: obj =   6.003500000e+05 inf =   4.762e+01 (4)
      4: obj =   6.053700000e+05 inf =   0.000e+00 (0)
*    13: obj =   5.553700000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    13: mip =     not found yet >=              -inf        (1; 0)
+    13: >>>>>   5.553700000e+05 >=   5.553700000e+05   0.0% (1; 0)
+    13: mip =   5.553700000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (115964 bytes)
Writing MIP solution to '/tmp/linopy-solve-w8td9sqt.sol'...
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 56 primals, 0 duals
Objective: 5.55e+05
Solver model: not available
Solver message: integer optimal

/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-sw4i4z2_.lp --output /tmp/linopy-solve-eyw8pdj1.sol
Reading problem data from '/tmp/linopy-problem-sw4i4z2_.lp'...
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
848 lines were read
GLPK Integer Optimizer 5.0
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
23 rows, 20 columns, 58 non-zeros
15 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 23
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
23 rows, 20 columns, 58 non-zeros
      0: obj =   6.003500000e+05 inf =   4.762e+01 (4)
      4: obj =   6.053700000e+05 inf =   0.000e+00 (0)
*    13: obj =   5.553700000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    13: mip =     not found yet >=              -inf        (1; 0)
+    13: >>>>>   5.553700000e+05 >=   5.553700000e+05   0.0% (1; 0)
+    13: mip =   5.553700000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (115964 bytes)
Writing MIP solution to '/tmp/linopy-solve-eyw8pdj1.sol'...
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 56 primals, 0 duals
Objective: 5.55e+05
Solver model: not available
Solver message: integer optimal

/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-liuyw1yi.lp --output /tmp/linopy-solve-rwloa9c6.sol
Reading problem data from '/tmp/linopy-problem-liuyw1yi.lp'...
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
848 lines were read
GLPK Integer Optimizer 5.0
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
23 rows, 20 columns, 58 non-zeros
15 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 23
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
23 rows, 20 columns, 58 non-zeros
      0: obj =   6.003500000e+05 inf =   4.762e+01 (4)
      4: obj =   6.053700000e+05 inf =   0.000e+00 (0)
*    13: obj =   5.553700000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    13: mip =     not found yet >=              -inf        (1; 0)
+    13: >>>>>   5.553700000e+05 >=   5.553700000e+05   0.0% (1; 0)
+    13: mip =   5.553700000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (115964 bytes)
Writing MIP solution to '/tmp/linopy-solve-rwloa9c6.sol'...
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 56 primals, 0 duals
Objective: 5.55e+05
Solver model: not available
Solver message: integer optimal

/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-w72k85my.lp --output /tmp/linopy-solve-51dx328j.sol
Reading problem data from '/tmp/linopy-problem-w72k85my.lp'...
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
848 lines were read
GLPK Integer Optimizer 5.0
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
23 rows, 20 columns, 58 non-zeros
15 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 23
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
23 rows, 20 columns, 58 non-zeros
      0: obj =   6.003500000e+05 inf =   4.762e+01 (4)
      4: obj =   6.053700000e+05 inf =   0.000e+00 (0)
*    13: obj =   5.553700000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    13: mip =     not found yet >=              -inf        (1; 0)
+    13: >>>>>   5.553700000e+05 >=   5.553700000e+05   0.0% (1; 0)
+    13: mip =   5.553700000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (115964 bytes)
Writing MIP solution to '/tmp/linopy-solve-51dx328j.sol'...
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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.2s
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 56 primals, 0 duals
Objective: 5.55e+05
Solver model: not available
Solver message: integer optimal

/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-up-time` to match existing coordinates.
  warnings.warn(
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-5nzoka31.lp --output /tmp/linopy-solve-jh2vdl5b.sol
Reading problem data from '/tmp/linopy-problem-5nzoka31.lp'...
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
848 lines were read
GLPK Integer Optimizer 5.0
112 rows, 56 columns, 282 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
23 rows, 20 columns, 58 non-zeros
15 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 23
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
23 rows, 20 columns, 58 non-zeros
      0: obj =   6.003500000e+05 inf =   4.762e+01 (4)
      4: obj =   6.053700000e+05 inf =   0.000e+00 (0)
*    13: obj =   5.553700000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    13: mip =     not found yet >=              -inf        (1; 0)
+    13: >>>>>   5.553700000e+05 >=   5.553700000e+05   0.0% (1; 0)
+    13: mip =   5.553700000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (115964 bytes)
Writing MIP solution to '/tmp/linopy-solve-jh2vdl5b.sol'...
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.23.0/lib/python3.11/site-packages/linopy/model.py:607: UserWarning: Reindexing constraint `Generator-com-down-time` to match existing coordinates.
  warnings.warn(
<__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
WARNING:linopy.solvers:Dual values of MILP couldn't be parsed
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 40 primals, 0 duals
Objective: 3.75e+05
Solver model: not available
Solver message: integer optimal

GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-46wmm_wv.lp --output /tmp/linopy-solve-zcuwurw_.sol
Reading problem data from '/tmp/linopy-problem-46wmm_wv.lp'...
80 rows, 40 columns, 196 non-zeros
30 integer variables, all of which are binary
606 lines were read
GLPK Integer Optimizer 5.0
80 rows, 40 columns, 196 non-zeros
30 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
13 rows, 12 columns, 30 non-zeros
9 integer variables, all of which are binary
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+03  ratio =  1.000e+03
GM: min|aij| =  5.623e-01  max|aij| =  1.778e+00  ratio =  3.162e+00
EQ: min|aij| =  3.162e-01  max|aij| =  1.000e+00  ratio =  3.162e+00
2N: min|aij| =  1.953e-01  max|aij| =  1.000e+00  ratio =  5.120e+00
Constructing initial basis...
Size of triangular part is 13
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
13 rows, 12 columns, 30 non-zeros
      0: obj =   4.203500000e+05 inf =   4.762e+01 (4)
      3: obj =   4.253500000e+05 inf =   0.000e+00 (0)
*    10: obj =   3.753700000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    10: mip =     not found yet >=              -inf        (1; 0)
+    10: >>>>>   3.753700000e+05 >=   3.753700000e+05   0.0% (1; 0)
+    10: mip =   3.753700000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (91756 bytes)
Writing MIP solution to '/tmp/linopy-solve-zcuwurw_.sol'...
[34]:
pd.concat(
    {"Active": nu.generators_t.status.astype(bool), "Output": nu.generators_t.p}, axis=1
)
[34]:
Active Output
Generator-com coal gas coal gas
snapshot
0 True True 3900.0 100.0
1 True True 4900.0 100.0
2 False True 0.0 700.0
3 False True 0.0 800.0
4 True False 4000.0 0.0
5 True True 3900.0 100.0
6 True True 4900.0 100.0
7 False True 0.0 700.0
8 False True 0.0 800.0
9 True False 4000.0 0.0
10 True True 3900.0 100.0
11 True True 4900.0 100.0
12 False True 0.0 700.0
13 False True 0.0 800.0
14 True False 4000.0 0.0
15 True True 3900.0 100.0
16 True True 4900.0 100.0
17 False True 0.0 700.0
18 False True 0.0 800.0
19 True False 4000.0 0.0
20 True True 3900.0 100.0
21 True True 4900.0 100.0
22 False True 0.0 700.0
23 False True 0.0 800.0
24 True False 4000.0 0.0
25 True True 3900.0 100.0
26 True True 4900.0 100.0
27 False True 0.0 700.0
28 False True 0.0 800.0
29 True False 4000.0 0.0