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
ERROR 1: PROJ: proj_create_from_database: Open of /home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/latest/share/proj failed

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()
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.03s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-ssm8af52.lp --output /tmp/linopy-solve-hax0vogt.sol
Reading problem data from '/tmp/linopy-problem-ssm8af52.lp'...
36 rows, 32 columns, 84 non-zeros
24 integer variables, all of which are binary
244 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-hax0vogt.sol'...

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

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
[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()
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.03s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-etk4c5_i.lp --output /tmp/linopy-solve-prbl__x0.sol
Reading problem data from '/tmp/linopy-problem-etk4c5_i.lp'...
39 rows, 32 columns, 95 non-zeros
24 integer variables, all of which are binary
263 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-prbl__x0.sol'...

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

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
[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.
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.03s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-et8qnvsp.lp --output /tmp/linopy-solve-g42e5cxc.sol
Reading problem data from '/tmp/linopy-problem-et8qnvsp.lp'...
40 rows, 32 columns, 94 non-zeros
24 integer variables, all of which are binary
264 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-g42e5cxc.sol'...

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

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
[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()
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.03s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-te6wq5me.lp --output /tmp/linopy-solve-89fcntal.sol
Reading problem data from '/tmp/linopy-problem-te6wq5me.lp'...
39 rows, 32 columns, 93 non-zeros
24 integer variables, all of which are binary
269 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-89fcntal.sol'...

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

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
[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()
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.02s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-cl8vujne.lp --output /tmp/linopy-solve-cz03ylm9.sol
Reading problem data from '/tmp/linopy-problem-cl8vujne.lp'...
40 rows, 12 columns, 56 non-zeros
208 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-cz03ylm9.sol'...

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

INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper, Generator-fix-p-ramp_limit_up, Generator-fix-p-ramp_limit_down were not assigned to the network.
[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()
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.03s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-v3bgjmbw.lp --output /tmp/linopy-solve-3a3g309a.sol
Reading problem data from '/tmp/linopy-problem-v3bgjmbw.lp'...
41 rows, 13 columns, 73 non-zeros
227 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-3a3g309a.sol'...

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

/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/latest/lib/python3.11/site-packages/pypsa/optimization/optimize.py:357: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.
The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.

For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.


  n.df(c)[attr + "_opt"].update(df)
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Generator-fix-p-lower, Generator-fix-p-upper, Generator-ext-p-lower, Generator-ext-p-upper, Generator-ext-p-ramp_limit_up, Generator-ext-p-ramp_limit_down were not assigned to the network.
[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()
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-lp7cwlrd.lp --output /tmp/linopy-solve-lqpf54ea.sol
Reading problem data from '/tmp/linopy-problem-lp7cwlrd.lp'...
61 rows, 35 columns, 144 non-zeros
21 integer variables, all of which are binary
384 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-lqpf54ea.sol'...

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

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
[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_mod                      0.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
marginal_cost_quadratic        0.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
stand_by_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
weight                         1.0
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])
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-0ql9vcjy.lp --output /tmp/linopy-solve-fhatczmx.sol
Reading problem data from '/tmp/linopy-problem-0ql9vcjy.lp'...
96 rows, 56 columns, 253 non-zeros
42 integer variables, all of which are binary
646 lines were read
GLPK Integer Optimizer 5.0
96 rows, 56 columns, 253 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 (114764 bytes)
Writing MIP solution to '/tmp/linopy-solve-fhatczmx.sol'...

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

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-j8xgwwl7.lp --output /tmp/linopy-solve-paukdgz1.sol
Reading problem data from '/tmp/linopy-problem-j8xgwwl7.lp'...
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
651 lines were read
GLPK Integer Optimizer 5.0
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
27 rows, 22 columns, 68 non-zeros
16 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 27
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
27 rows, 22 columns, 68 non-zeros
      0: obj =   5.953500000e+05 inf =   3.962e+01 (3)
      3: obj =   5.954200000e+05 inf =   0.000e+00 (0)
*    13: obj =   5.504200000e+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.504200000e+05 >=   5.504200000e+05   0.0% (1; 0)
+    13: mip =   5.504200000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (117310 bytes)
Writing MIP solution to '/tmp/linopy-solve-paukdgz1.sol'...

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.50e+05
Solver model: not available
Solver message: integer optimal

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-xyi_vj2c.lp --output /tmp/linopy-solve-q6r4quaf.sol
Reading problem data from '/tmp/linopy-problem-xyi_vj2c.lp'...
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
651 lines were read
GLPK Integer Optimizer 5.0
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
27 rows, 23 columns, 68 non-zeros
17 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 27
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
27 rows, 23 columns, 68 non-zeros
      0: obj =   5.953500000e+05 inf =   4.762e+01 (4)
      4: obj =   5.954400000e+05 inf =   0.000e+00 (0)
*    15: obj =   5.504400000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    15: mip =     not found yet >=              -inf        (1; 0)
+    15: >>>>>   5.504400000e+05 >=   5.504400000e+05   0.0% (1; 0)
+    15: mip =   5.504400000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (117479 bytes)
Writing MIP solution to '/tmp/linopy-solve-q6r4quaf.sol'...

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.50e+05
Solver model: not available
Solver message: integer optimal

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-s256x387.lp --output /tmp/linopy-solve-0mbfeppl.sol
Reading problem data from '/tmp/linopy-problem-s256x387.lp'...
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
651 lines were read
GLPK Integer Optimizer 5.0
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
27 rows, 23 columns, 68 non-zeros
17 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 27
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
27 rows, 23 columns, 68 non-zeros
      0: obj =   5.953500000e+05 inf =   4.762e+01 (4)
      4: obj =   5.954400000e+05 inf =   0.000e+00 (0)
*    15: obj =   5.504400000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    15: mip =     not found yet >=              -inf        (1; 0)
+    15: >>>>>   5.504400000e+05 >=   5.504400000e+05   0.0% (1; 0)
+    15: mip =   5.504400000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (117479 bytes)
Writing MIP solution to '/tmp/linopy-solve-0mbfeppl.sol'...

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.50e+05
Solver model: not available
Solver message: integer optimal

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-nkpku7n6.lp --output /tmp/linopy-solve-oj5kt9i0.sol
Reading problem data from '/tmp/linopy-problem-nkpku7n6.lp'...
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
651 lines were read
GLPK Integer Optimizer 5.0
97 rows, 56 columns, 255 non-zeros
42 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
27 rows, 23 columns, 68 non-zeros
17 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 27
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
27 rows, 23 columns, 68 non-zeros
      0: obj =   5.953500000e+05 inf =   4.762e+01 (4)
      4: obj =   5.954400000e+05 inf =   0.000e+00 (0)
*    15: obj =   5.504400000e+05 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Integer optimization begins...
Long-step dual simplex will be used
+    15: mip =     not found yet >=              -inf        (1; 0)
+    15: >>>>>   5.504400000e+05 >=   5.504400000e+05   0.0% (1; 0)
+    15: mip =   5.504400000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (117479 bytes)
Writing MIP solution to '/tmp/linopy-solve-oj5kt9i0.sol'...

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.50e+05
Solver model: not available
Solver message: integer optimal

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
INFO:linopy.model: Solve problem using Glpk solver
INFO:linopy.io: Writing time: 0.04s
INFO:linopy.solvers:GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --lp /tmp/linopy-problem-y78tpsks.lp --output /tmp/linopy-solve-gkzg9mz7.sol
Reading problem data from '/tmp/linopy-problem-y78tpsks.lp'...
69 rows, 40 columns, 177 non-zeros
30 integer variables, all of which are binary
461 lines were read
GLPK Integer Optimizer 5.0
69 rows, 40 columns, 177 non-zeros
30 integer variables, all of which are binary
Preprocessing...
3 hidden packing inequaliti(es) were detected
17 rows, 15 columns, 40 non-zeros
11 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 17
Solving LP relaxation...
GLPK Simplex Optimizer 5.0
17 rows, 15 columns, 40 non-zeros
      0: obj =   4.153500000e+05 inf =   4.762e+01 (4)
      3: obj =   4.154200000e+05 inf =   0.000e+00 (0)
*    11: obj =   3.704200000e+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.704200000e+05 >=   3.704200000e+05   0.0% (1; 0)
+    11: mip =   3.704200000e+05 >=     tree is empty   0.0% (0; 1)
INTEGER OPTIMAL SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.1 Mb (86439 bytes)
Writing MIP solution to '/tmp/linopy-solve-gkzg9mz7.sol'...

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.70e+05
Solver model: not available
Solver message: integer optimal

INFO:pypsa.optimization.optimize:No shadow prices were assigned to the network.
[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 False 4000.0 0.0
6 True False 5000.0 0.0
7 False True 0.0 700.0
8 False True 0.0 800.0
9 True True 3900.0 100.0
10 True False 4000.0 0.0
11 True False 5000.0 0.0
12 False True 0.0 700.0
13 False True 0.0 800.0
14 True True 3900.0 100.0
15 True False 4000.0 0.0
16 True False 5000.0 0.0
17 False True 0.0 700.0
18 False True 0.0 800.0
19 True True 3900.0 100.0
20 True False 4000.0 0.0
21 True False 5000.0 0.0
22 False True 0.0 700.0
23 False True 0.0 800.0
24 True True 3900.0 100.0
25 True False 4000.0 0.0
26 True False 5000.0 0.0
27 False True 0.0 700.0
28 False True 0.0 800.0
29 True True 3900.0 100.0