Note
You can download this example as a Jupyter notebook or start it in interactive mode.
Security-Constrained Optimisation
In this example, the dispatch of generators is optimised using the security-constrained linear OPF, to guaranteed that no branches are overloaded by certain branch outages.
[1]:
import pypsa, os
import numpy as np
[2]:
network = pypsa.examples.scigrid_de(from_master=True)
WARNING:pypsa.io:
Importing PyPSA from older version of PyPSA than current version.
Please read the release notes at https://pypsa.org/doc/release_notes.html
carefully to prepare your network for import.
Currently used PyPSA version [0, 18, 1], imported network file PyPSA version [0, 17, 1].
INFO:pypsa.io:Imported network scigrid-de.nc has buses, generators, lines, loads, storage_units, transformers
There are some infeasibilities without line extensions.
[3]:
for line_name in ["316","527","602"]:
network.lines.loc[line_name,"s_nom"] = 1200
now = network.snapshots[0]
Performing security-constrained linear OPF
[4]:
branch_outages = network.lines.index[:15]
network.sclopf(now,branch_outages=branch_outages, solver_name='cbc')
INFO:pypsa.opf:Building pyomo model using `kirchhoff` formulation
/home/docs/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/scipy/sparse/linalg/dsolve/linsolve.py:318: SparseEfficiencyWarning: splu requires CSC matrix format
warn('splu requires CSC matrix format', SparseEfficiencyWarning)
/home/docs/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/contingency.py:70: RuntimeWarning: divide by zero encountered in true_divide
denominator = csr_matrix((1/(1-np.diag(branch_PTDF)),(r_[:num_branches],r_[:num_branches])))
WARNING:pypsa.contingency:No type given for 1, assuming it is a line
WARNING:pypsa.contingency:No type given for 2, assuming it is a line
WARNING:pypsa.contingency:No type given for 3, assuming it is a line
WARNING:pypsa.contingency:No type given for 4, assuming it is a line
WARNING:pypsa.contingency:No type given for 5, assuming it is a line
WARNING:pypsa.contingency:No type given for 6, assuming it is a line
WARNING:pypsa.contingency:No type given for 7, assuming it is a line
WARNING:pypsa.contingency:No type given for 8, assuming it is a line
WARNING:pypsa.contingency:No type given for 9, assuming it is a line
WARNING:pypsa.contingency:No type given for 10, assuming it is a line
WARNING:pypsa.contingency:No type given for 11, assuming it is a line
WARNING:pypsa.contingency:No type given for 12, assuming it is a line
WARNING:pypsa.contingency:No type given for 13, assuming it is a line
WARNING:pypsa.contingency:No type given for 14, assuming it is a line
WARNING:pypsa.contingency:No type given for 15, assuming it is a line
INFO:pypsa.opf:Solving model using cbc
WARNING:pyomo.solvers:Could not locate the 'cbc' executable, which is required for solver cbc
---------------------------------------------------------------------------
ApplicationError Traceback (most recent call last)
/tmp/ipykernel_792/3955788825.py in <module>
1 branch_outages = network.lines.index[:15]
----> 2 network.sclopf(now,branch_outages=branch_outages, solver_name='cbc')
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/contingency.py in network_sclopf(network, snapshots, branch_outages, solver_name, pyomo, skip_pre, extra_functionality, solver_options, keep_files, formulation, ptdf_tolerance)
368 skip_pre=True, extra_functionality=_extra_functionality,
369 solver_options=solver_options, keep_files=keep_files,
--> 370 formulation=formulation, **pyomo_kwargs)
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/components.py in lopf(self, snapshots, pyomo, solver_name, solver_options, solver_logfile, formulation, keep_files, extra_functionality, multi_investment_periods, **kwargs)
646
647 if pyomo:
--> 648 return network_lopf(self, **args)
649 else:
650 return network_lopf_lowmem(self, **args)
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/opf.py in network_lopf(network, snapshots, solver_name, solver_io, skip_pre, extra_functionality, multi_investment_periods, solver_logfile, solver_options, keep_files, formulation, ptdf_tolerance, free_memory, extra_postprocessing)
1663 solver_logfile=solver_logfile, solver_options=solver_options,
1664 keep_files=keep_files, free_memory=free_memory,
-> 1665 extra_postprocessing=extra_postprocessing)
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/opf.py in network_lopf_solve(network, snapshots, formulation, solver_options, solver_logfile, keep_files, free_memory, extra_postprocessing)
1563 network.results = network.opt.solve(*args, suffixes=["dual"], keepfiles=keep_files, logfile=solver_logfile, options=solver_options)
1564 else:
-> 1565 network.results = network.opt.solve(*args, suffixes=["dual"], keepfiles=keep_files, logfile=solver_logfile, options=solver_options)
1566
1567 if logger.isEnabledFor(logging.INFO):
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pyomo/opt/base/solvers.py in solve(self, *args, **kwds)
510 """ Solve the problem """
511
--> 512 self.available(exception_flag=True)
513 #
514 # If the inputs are models, then validate that they have been
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pyomo/opt/solver/shellcmd.py in available(self, exception_flag)
123 if exception_flag:
124 msg = "No executable found for solver '%s'"
--> 125 raise ApplicationError(msg % self.name)
126 return False
127 return True
ApplicationError: No executable found for solver 'cbc'
For the PF, set the P to the optimised P.
[5]:
network.generators_t.p_set = network.generators_t.p_set.reindex(columns=network.generators.index)
network.generators_t.p_set.loc[now] = network.generators_t.p.loc[now]
network.storage_units_t.p_set = (network.storage_units_t.p_set
.reindex(columns=network.storage_units.index))
network.storage_units_t.p_set.loc[now] = network.storage_units_t.p.loc[now]
Check no lines are overloaded with the linear contingency analysis
[6]:
p0_test = network.lpf_contingency(now,branch_outages=branch_outages)
p0_test
INFO:pypsa.pf:Performing linear load-flow on AC sub-network SubNetwork 0 for snapshot(s) DatetimeIndex(['2011-01-01'], dtype='datetime64[ns]', freq=None)
/home/docs/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/scipy/sparse/linalg/dsolve/linsolve.py:318: SparseEfficiencyWarning: splu requires CSC matrix format
warn('splu requires CSC matrix format', SparseEfficiencyWarning)
/home/docs/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/contingency.py:70: RuntimeWarning: divide by zero encountered in true_divide
denominator = csr_matrix((1/(1-np.diag(branch_PTDF)),(r_[:num_branches],r_[:num_branches])))
WARNING:pypsa.contingency:No type given for 1, assuming it is a line
WARNING:pypsa.contingency:No type given for 2, assuming it is a line
WARNING:pypsa.contingency:No type given for 3, assuming it is a line
WARNING:pypsa.contingency:No type given for 4, assuming it is a line
WARNING:pypsa.contingency:No type given for 5, assuming it is a line
WARNING:pypsa.contingency:No type given for 6, assuming it is a line
WARNING:pypsa.contingency:No type given for 7, assuming it is a line
WARNING:pypsa.contingency:No type given for 8, assuming it is a line
WARNING:pypsa.contingency:No type given for 9, assuming it is a line
WARNING:pypsa.contingency:No type given for 10, assuming it is a line
WARNING:pypsa.contingency:No type given for 11, assuming it is a line
WARNING:pypsa.contingency:No type given for 12, assuming it is a line
WARNING:pypsa.contingency:No type given for 13, assuming it is a line
WARNING:pypsa.contingency:No type given for 14, assuming it is a line
WARNING:pypsa.contingency:No type given for 15, assuming it is a line
[6]:
| base | (Line, 1) | (Line, 2) | (Line, 3) | (Line, 4) | (Line, 5) | (Line, 6) | (Line, 7) | (Line, 8) | (Line, 9) | (Line, 10) | (Line, 11) | (Line, 12) | (Line, 13) | (Line, 14) | (Line, 15) | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| name | |||||||||||||||||
| Transformer | 2 | -38405.760474 | -38405.760474 | -37524.606180 | -38651.314748 | -38024.054191 | -38332.574280 | -38404.456639 | -38404.837538 | -38404.582759 | -38405.995642 | -38406.675222 | -38467.252543 | -38428.699550 | -38427.275047 | -38406.673695 | -38405.860448 |
| 5 | -3147.518795 | -3147.518795 | -3812.294807 | -2693.431047 | -3566.113045 | -2974.740546 | -3147.650764 | -3147.612211 | -3147.637999 | -3147.250645 | -3146.470125 | -2982.706686 | -3138.643080 | -3139.194257 | -3146.471875 | -3147.399893 | |
| 10 | 1134.736147 | 1134.736147 | 1108.369316 | 1133.614815 | 1128.000480 | 1228.312398 | 1062.398182 | 1083.530812 | 1069.395423 | 1134.809567 | 1135.015857 | 1005.662933 | 1876.792258 | 1830.711003 | 1135.015390 | 1134.762235 | |
| 12 | -751.239426 | -751.239426 | -743.548394 | -750.788863 | -748.611004 | -774.731882 | -628.209969 | -664.151483 | -640.110592 | -751.252547 | -751.288140 | -717.041121 | -1485.421235 | -1439.828970 | -751.288059 | -751.242977 | |
| 13 | -75.637982 | -75.637982 | -59.843461 | -74.036117 | -65.999162 | -75.343146 | -75.823972 | -75.769637 | -75.805981 | 53.962071 | -247.060201 | -57.859489 | -71.776136 | -72.015954 | -246.774034 | 56.902183 | |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| Line | 855 | 322.269748 | 322.269748 | 327.492701 | 322.591660 | 324.632638 | 323.504120 | 322.252135 | 322.257280 | 322.253839 | 322.324971 | 322.477745 | 325.024802 | 322.674975 | 322.649811 | 322.477397 | 322.287290 |
| 856 | 529.037526 | 529.037526 | 537.642110 | 529.620629 | 533.213552 | 531.416054 | 529.010405 | 529.018328 | 529.013029 | 529.134182 | 529.401488 | 533.693253 | 529.682144 | 529.642114 | 529.400881 | 529.068149 | |
| 857 | 685.362531 | 685.362531 | 740.292181 | 683.951778 | 684.639762 | 668.491429 | 685.035552 | 685.131075 | 685.067180 | 685.394175 | 685.489784 | 702.107908 | 691.160513 | 690.800462 | 685.489571 | 685.379613 | |
| 858 | 157.849501 | 157.849501 | 160.286124 | 158.014623 | 159.032057 | 158.523046 | 157.841821 | 157.844065 | 157.842564 | 157.876872 | 157.952567 | 159.167897 | 158.032042 | 158.020707 | 157.952395 | 157.858173 | |
| 859 | 768.482235 | 768.482235 | 786.076837 | 769.094771 | 773.938314 | 769.808634 | 768.411094 | 768.431877 | 768.417976 | 768.611853 | 768.971217 | 776.447560 | 769.959749 | 769.867997 | 768.970401 | 768.524086 |
948 rows × 16 columns
Check loading as per unit of s_nom in each contingency
[7]:
max_loading = abs(p0_test.divide(network.passive_branches().s_nom,axis=0)).describe().loc["max"]
max_loading
[7]:
base 52.006682
(Line, 1) 104.008569
(Line, 2) 52.006682
(Line, 3) 52.006682
(Line, 4) 52.006682
(Line, 5) 52.006682
(Line, 6) 52.006682
(Line, 7) 52.006682
(Line, 8) 52.006682
(Line, 9) 52.006682
(Line, 10) 52.006682
(Line, 11) 52.006682
(Line, 12) 52.006682
(Line, 13) 52.006682
(Line, 14) 52.006682
(Line, 15) 52.006682
Name: max, dtype: float64
[8]:
np.allclose(max_loading,np.ones((len(max_loading))))
[8]:
False