Note
You can download this example as a Jupyter notebook or start it in interactive mode.
Non-linear power flow after LOPF#
In this example, the dispatch of generators is optimised using the linear OPF, then a non-linear power flow is run on the resulting dispatch.
Data sources#
Grid: based on SciGRID Version 0.2 which is based on OpenStreetMap.
Load size and location: based on Landkreise (NUTS 3) GDP and population.
Load time series: from ENTSO-E hourly data, scaled up uniformly by factor 1.12 (a simplification of the methodology in Schumacher, Hirth (2015)).
Conventional power plant capacities and locations: BNetzA list.
Wind and solar capacities and locations: EEG Stammdaten, based on http://www.energymap.info/download.html, which represents capacities at the end of 2014. Units without PLZ are removed.
Wind and solar time series: REatlas, Andresen et al, “Validation of Danish wind time series from a new global renewable energy atlas for energy system analysis,” Energy 93 (2015) 1074 - 1088.
Where SciGRID nodes have been split into 220kV and 380kV substations, all load and generation is attached to the 220kV substation.
Warnings#
The data behind the notebook is no longer supported. See PyPSA/pypsa-eur for a newer model that covers the whole of Europe.
This dataset is ONLY intended to demonstrate the capabilities of PyPSA and is NOT (yet) accurate enough to be used for research purposes.
Known problems include:
Rough approximations have been made for missing grid data, e.g. 220kV-380kV transformers and connections between close sub-stations missing from OSM.
There appears to be some unexpected congestion in parts of the network, which may mean for example that the load attachment method (by Voronoi cell overlap with Landkreise) isn’t working, particularly in regions with a high density of substations.
Attaching power plants to the nearest high voltage substation may not reflect reality.
There is no proper n-1 security in the calculations - this can either be simulated with a blanket e.g. 70% reduction in thermal limits (as done here) or a proper security constrained OPF (see e.g. http://www.pypsa.org/examples/scigrid-sclopf.ipynb).
The borders and neighbouring countries are not represented.
Hydroelectric power stations are not modelled accurately.
The marginal costs are illustrative, not accurate.
Only the first day of 2011 is in the github dataset, which is not representative. The full year of 2011 can be downloaded at http://www.pypsa.org/examples/scigrid-with-load-gen-trafos-2011.zip.
The ENTSO-E total load for Germany may not be scaled correctly; it is scaled up uniformly by factor 1.12 (a simplification of the methodology in Schumacher, Hirth (2015), which suggests monthly factors).
Biomass from the EEG Stammdaten are not read in at the moment.
Power plant start up costs, ramping limits/costs, minimum loading rates are not considered.
[1]:
import pypsa
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.24.0/lib/python3.11/site-packages/pypsa/networkclustering.py:16: UserWarning: The namespace `pypsa.networkclustering` is deprecated and will be removed in PyPSA v0.24. Please use `pypsa.clustering.spatial instead`.
warnings.warn(
[2]:
network = pypsa.examples.scigrid_de(from_master=True)
WARNING:pypsa.io:Importing network from PyPSA version v0.17.1 while current version is v0.24.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 scigrid-de.nc has buses, generators, lines, loads, storage_units, transformers
Plot the distribution of the load and of generating tech
[3]:
fig, ax = plt.subplots(
1, 1, subplot_kw={"projection": ccrs.EqualEarth()}, figsize=(8, 8)
)
load_distribution = (
network.loads_t.p_set.loc[network.snapshots[0]].groupby(network.loads.bus).sum()
)
network.plot(bus_sizes=1e-5 * load_distribution, ax=ax, title="Load distribution");
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.24.0/lib/python3.11/site-packages/cartopy/mpl/style.py:76: UserWarning: facecolor will have no effect as it has been defined as "never".
warnings.warn('facecolor will have no effect as it has been '
[4]:
network.generators.groupby("carrier")["p_nom"].sum()
[4]:
carrier
Brown Coal 20879.500000
Gas 23913.130000
Geothermal 31.700000
Hard Coal 25312.600000
Multiple 152.700000
Nuclear 12068.000000
Oil 2710.200000
Other 3027.800000
Run of River 3999.100000
Solar 37041.524779
Storage Hydro 1445.000000
Waste 1645.900000
Wind Offshore 2973.500000
Wind Onshore 37339.895329
Name: p_nom, dtype: float64
[5]:
network.storage_units.groupby("carrier")["p_nom"].sum()
[5]:
carrier
Pumped Hydro 9179.5
Name: p_nom, dtype: float64
[6]:
techs = ["Gas", "Brown Coal", "Hard Coal", "Wind Offshore", "Wind Onshore", "Solar"]
n_graphs = len(techs)
n_cols = 3
if n_graphs % n_cols == 0:
n_rows = n_graphs // n_cols
else:
n_rows = n_graphs // n_cols + 1
fig, axes = plt.subplots(
nrows=n_rows, ncols=n_cols, subplot_kw={"projection": ccrs.EqualEarth()}
)
size = 6
fig.set_size_inches(size * n_cols, size * n_rows)
for i, tech in enumerate(techs):
i_row = i // n_cols
i_col = i % n_cols
ax = axes[i_row, i_col]
gens = network.generators[network.generators.carrier == tech]
gen_distribution = (
gens.groupby("bus").sum()["p_nom"].reindex(network.buses.index, fill_value=0.0)
)
network.plot(ax=ax, bus_sizes=2e-5 * gen_distribution)
ax.set_title(tech)
fig.tight_layout()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.24.0/lib/python3.11/site-packages/cartopy/mpl/style.py:76: UserWarning: facecolor will have no effect as it has been defined as "never".
warnings.warn('facecolor will have no effect as it has been '
Run Linear Optimal Power Flow on the first day of 2011.
To approximate n-1 security and allow room for reactive power flows, don’t allow any line to be loaded above 70% of their thermal rating
[7]:
contingency_factor = 0.7
network.lines.s_max_pu = contingency_factor
There are some infeasibilities without small extensions
[8]:
network.lines.loc[["316", "527", "602"], "s_nom"] = 1715
We performing a linear OPF for one day, 4 snapshots at a time.
[9]:
group_size = 4
network.storage_units.state_of_charge_initial = 0.0
for i in range(int(24 / group_size)):
# set the initial state of charge based on previous round
if i:
network.storage_units.state_of_charge_initial = (
network.storage_units_t.state_of_charge.loc[
network.snapshots[group_size * i - 1]
]
)
network.optimize(
network.snapshots[group_size * i : group_size * i + group_size],
solver_name="cbc",
)
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
INFO:linopy.model: Solve linear problem using Cbc solver
INFO:linopy.io:Writing objective.
Writing constraints.: 100%|██████████| 15/15 [00:00<00:00, 78.23it/s]
Writing continuous variables.: 100%|██████████| 7/7 [00:00<00:00, 253.01it/s]
INFO:linopy.io: Writing time: 0.23s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 9940 primals, 23828 duals
Objective: 1.45e+06
Solver model: not available
Solver message: Optimal - objective value 1449687.25014697
Welcome to the CBC MILP Solver
Version: 2.10.10
Build Date: Apr 19 2023
command line - cbc -printingOptions all -import /tmp/linopy-problem-xy4o4n1h.lp -solve -solu /tmp/linopy-solve-hbb7ed7x.sol (default strategy 1)
Option for printingOptions changed from normal to all
Presolve 2374 (-21454) rows, 4321 (-5619) columns and 16165 (-28653) elements
Perturbing problem by 0.001% of 2449.2813 - largest nonzero change 0.00099323312 ( 0.01516664%) - largest zero change 0.00099115148
0 Obj 88145.87 Primal inf 5088423.3 (2169) Dual inf 643.19931 (4)
122 Obj 18794.556 Primal inf 3786129.8 (2140)
244 Obj 18794.556 Primal inf 3187310.3 (2069)
366 Obj 18796.14 Primal inf 2963428.8 (2038)
488 Obj 18796.715 Primal inf 2846998.6 (1990)
610 Obj 18797.754 Primal inf 7577693.4 (1993)
732 Obj 18799.448 Primal inf 2414939.2 (1876)
854 Obj 18800.396 Primal inf 2301237.2 (1802)
976 Obj 18802.076 Primal inf 2760961.2 (1744)
1098 Obj 18805.201 Primal inf 4747823.5 (1712)
1220 Obj 18806.81 Primal inf 5421341.6 (1636)
1342 Obj 18808.738 Primal inf 4412286.2 (1529)
1464 Obj 18811.035 Primal inf 2928402.3 (1413)
1586 Obj 22629.283 Primal inf 1758589.6 (1313)
1708 Obj 22632.404 Primal inf 2583963.1 (1218)
1830 Obj 22636.13 Primal inf 3940344.6 (1228)
1952 Obj 22640.767 Primal inf 3402892.1 (1090)
2074 Obj 22646.236 Primal inf 1648889 (893)
2196 Obj 121662.16 Primal inf 72850654 (740)
2318 Obj 361205.88 Primal inf 93351879 (927)
2440 Obj 670115.98 Primal inf 56792064 (597)
2562 Obj 843636.42 Primal inf 1207774.3 (439)
2684 Obj 1104652.9 Primal inf 389290.34 (370)
2806 Obj 1315871.3 Primal inf 14459.471 (178)
2928 Obj 1427248.6 Primal inf 24800.465 (127)
3050 Obj 1449427.4 Primal inf 40.13038 (18)
3085 Obj 1449694.6
3085 Obj 1449687.3 Dual inf 4.902528e-05 (2)
3088 Obj 1449687.3
Optimal - objective value 1449687.3
After Postsolve, objective 1449687.3, infeasibilities - dual 214.20597 (7), primal 1.7945026e-06 (7)
Presolved model was optimal, full model needs cleaning up
0 Obj 1449687.3 Dual inf 2.142059 (7)
End of values pass after 10 iterations
10 Obj 1449687.3
Optimal - objective value 1449687.3
Optimal objective 1449687.25 - 3098 iterations time 0.362, Presolve 0.02
Total time (CPU seconds): 0.55 (Wallclock seconds): 0.52
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Kirchhoff-Voltage-Law were not assigned to the network.
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
INFO:linopy.model: Solve linear problem using Cbc solver
INFO:linopy.io:Writing objective.
Writing constraints.: 100%|██████████| 15/15 [00:00<00:00, 81.25it/s]
Writing continuous variables.: 100%|██████████| 7/7 [00:00<00:00, 244.63it/s]
INFO:linopy.io: Writing time: 0.23s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 9940 primals, 23828 duals
Objective: 8.74e+05
Solver model: not available
Solver message: Optimal - objective value 873763.90232907
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Kirchhoff-Voltage-Law were not assigned to the network.
Welcome to the CBC MILP Solver
Version: 2.10.10
Build Date: Apr 19 2023
command line - cbc -printingOptions all -import /tmp/linopy-problem-2shmfqqt.lp -solve -solu /tmp/linopy-solve-y49a7o_f.sol (default strategy 1)
Option for printingOptions changed from normal to all
Presolve 2398 (-21430) rows, 4362 (-5578) columns and 16308 (-28510) elements
Perturbing problem by 0.001% of 2998.2956 - largest nonzero change 0.00099191028 ( 0.065266124%) - largest zero change 0.00098701061
0 Obj 81182.754 Primal inf 4978100.6 (2198) Dual inf 1089.1409 (4)
122 Obj 11831.44 Primal inf 3766653.8 (2155)
244 Obj 11831.44 Primal inf 3315166.8 (2103)
366 Obj 11831.75 Primal inf 2953190.7 (2055)
488 Obj 11834.627 Primal inf 3630596.4 (1984)
610 Obj 11835.54 Primal inf 2772497.4 (1963)
732 Obj 11837.297 Primal inf 3102886 (1943)
854 Obj 11837.881 Primal inf 2862875.9 (1869)
976 Obj 11839.34 Primal inf 3424482.3 (1824)
1098 Obj 11840.686 Primal inf 4303892.4 (1757)
1220 Obj 11843.134 Primal inf 3418470.4 (1656)
1342 Obj 11844.848 Primal inf 2359939 (1563)
1464 Obj 11847.643 Primal inf 2459170.5 (1448)
1586 Obj 11849.765 Primal inf 12799719 (1613)
1708 Obj 11853.249 Primal inf 10977995 (1526)
1830 Obj 11857.014 Primal inf 3682235.8 (1130)
1952 Obj 11861.46 Primal inf 2417292.3 (1201)
2074 Obj 11867.139 Primal inf 1282648.6 (887)
2196 Obj 20240.185 Primal inf 733162.46 (846)
2318 Obj 44373.571 Primal inf 1605040.2 (946)
2440 Obj 142737.02 Primal inf 2789905.1 (827)
2562 Obj 267523.29 Primal inf 21580745 (768)
2684 Obj 521893.06 Primal inf 9963160 (594)
2806 Obj 591547.19 Primal inf 10931492 (670)
2928 Obj 759444.72 Primal inf 10131743 (330)
3050 Obj 861917.81 Primal inf 12375.022 (131)
3172 Obj 872990.74 Primal inf 9277.2043 (81)
3266 Obj 873772.06
3266 Obj 873763.94 Dual inf 0.00078640246 (2)
3270 Obj 873763.9
Optimal - objective value 873763.9
After Postsolve, objective 873763.9, infeasibilities - dual 78.034695 (3), primal 9.1550862e-07 (3)
Presolved model was optimal, full model needs cleaning up
0 Obj 873763.9 Dual inf 0.78034665 (3)
End of values pass after 3 iterations
3 Obj 873763.9
Optimal - objective value 873763.9
Optimal objective 873763.9023 - 3273 iterations time 0.392, Presolve 0.03
Total time (CPU seconds): 0.60 (Wallclock seconds): 0.56
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
INFO:linopy.model: Solve linear problem using Cbc solver
INFO:linopy.io:Writing objective.
Writing constraints.: 100%|██████████| 15/15 [00:00<00:00, 81.36it/s]
Writing continuous variables.: 100%|██████████| 7/7 [00:00<00:00, 249.29it/s]
INFO:linopy.io: Writing time: 0.23s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 9940 primals, 23828 duals
Objective: 7.91e+05
Solver model: not available
Solver message: Optimal - objective value 790786.59488191
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Kirchhoff-Voltage-Law were not assigned to the network.
Welcome to the CBC MILP Solver
Version: 2.10.10
Build Date: Apr 19 2023
command line - cbc -printingOptions all -import /tmp/linopy-problem-96k08g19.lp -solve -solu /tmp/linopy-solve-q6xkhn5d.sol (default strategy 1)
Option for printingOptions changed from normal to all
Presolve 2458 (-21370) rows, 4430 (-5510) columns and 16535 (-28283) elements
Perturbing problem by 0.001% of 3268.792 - largest nonzero change 0.00099338525 ( 0.0062578095%) - largest zero change 0.00099328771
0 Obj -38.474412 Primal inf 5062095.5 (2261)
124 Obj -38.474412 Primal inf 3828339 (2220)
248 Obj -38.474412 Primal inf 3255443.4 (2172)
372 Obj -38.474412 Primal inf 2989752.7 (2133)
496 Obj -35.917673 Primal inf 2728944.5 (2069)
620 Obj -34.814278 Primal inf 11035160 (2056)
744 Obj -32.995215 Primal inf 7743498.5 (1971)
868 Obj -30.804241 Primal inf 8833459.4 (1907)
992 Obj -29.505447 Primal inf 4656231.2 (1775)
1116 Obj -28.18612 Primal inf 3589112.2 (1721)
1240 Obj -25.849398 Primal inf 31918935 (1698)
1364 Obj -24.940983 Primal inf 4631345.2 (1589)
1488 Obj -22.399434 Primal inf 6124081.4 (1497)
1612 Obj -20.074864 Primal inf 6354371.5 (1461)
1736 Obj 7643.0721 Primal inf 5274102.3 (1343)
1860 Obj 7646.345 Primal inf 12587994 (1217)
1984 Obj 7651.8656 Primal inf 4876545.5 (1078)
2108 Obj 7655.8583 Primal inf 4777023.8 (849)
2232 Obj 7719.2573 Primal inf 3442500.1 (885)
2356 Obj 13803.676 Primal inf 1578739.1 (869)
2480 Obj 95115.32 Primal inf 91602478 (1044)
2604 Obj 226156.69 Primal inf 1.4602469e+08 (896)
2728 Obj 369817.26 Primal inf 54731030 (612)
2852 Obj 494810.15 Primal inf 10646240 (553)
2976 Obj 550387.11 Primal inf 16648939 (485)
3100 Obj 707664.52 Primal inf 40817.296 (237)
3224 Obj 776753.89 Primal inf 12005.736 (138)
3348 Obj 790192.89 Primal inf 9241.6779 (47)
3399 Obj 790796.05
Optimal - objective value 790786.59
After Postsolve, objective 790786.59, infeasibilities - dual 18 (2), primal 9.8396307e-07 (2)
Presolved model was optimal, full model needs cleaning up
0 Obj 790786.59 Dual inf 0.1799998 (2)
End of values pass after 3 iterations
3 Obj 790786.59
Optimal - objective value 790786.59
Optimal objective 790786.5949 - 3402 iterations time 0.422, Presolve 0.02
Total time (CPU seconds): 0.61 (Wallclock seconds): 0.58
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
INFO:linopy.model: Solve linear problem using Cbc solver
INFO:linopy.io:Writing objective.
Writing constraints.: 100%|██████████| 15/15 [00:00<00:00, 78.35it/s]
Writing continuous variables.: 100%|██████████| 7/7 [00:00<00:00, 247.36it/s]
INFO:linopy.io: Writing time: 0.23s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 9940 primals, 23828 duals
Objective: 1.46e+06
Solver model: not available
Solver message: Optimal - objective value 1455232.67827293
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Kirchhoff-Voltage-Law were not assigned to the network.
Welcome to the CBC MILP Solver
Version: 2.10.10
Build Date: Apr 19 2023
command line - cbc -printingOptions all -import /tmp/linopy-problem-63oz_t6e.lp -solve -solu /tmp/linopy-solve-b040spvh.sol (default strategy 1)
Option for printingOptions changed from normal to all
Presolve 2447 (-21381) rows, 4425 (-5515) columns and 16507 (-28311) elements
Perturbing problem by 0.001% of 2240.9252 - largest nonzero change 0.00099874891 ( 0.0087681826%) - largest zero change 0.0009971789
0 Obj 25305.903 Primal inf 5111220.9 (2264) Dual inf 265.06173 (1)
123 Obj 7968.0747 Primal inf 3951358.7 (2228)
246 Obj 7968.0747 Primal inf 3356526.8 (2165)
369 Obj 7968.4997 Primal inf 3789404 (2127)
492 Obj 7968.6176 Primal inf 3334611.5 (2064)
615 Obj 7973.7355 Primal inf 3116964.2 (2021)
738 Obj 7977.4642 Primal inf 2795152.9 (1918)
861 Obj 7979.4215 Primal inf 2035235.1 (1835)
984 Obj 7980.1229 Primal inf 1887713.3 (1746)
1107 Obj 7981.5095 Primal inf 3443003.4 (1733)
1230 Obj 7983.8865 Primal inf 5200853.2 (1708)
1353 Obj 7985.7809 Primal inf 2187227.3 (1573)
1476 Obj 7988.0269 Primal inf 5442040.4 (1581)
1599 Obj 23724.589 Primal inf 5203808.8 (1402)
1722 Obj 23727.555 Primal inf 7811350.2 (1260)
1845 Obj 23730.856 Primal inf 43660730 (1187)
1968 Obj 23733.434 Primal inf 16678941 (1209)
2091 Obj 23737.19 Primal inf 9128159.7 (997)
2214 Obj 37302.141 Primal inf 7097554.6 (992)
2337 Obj 107236.12 Primal inf 28621079 (857)
2460 Obj 388222.81 Primal inf 1.0426889e+08 (669)
2583 Obj 767754.56 Primal inf 363722.22 (478)
2706 Obj 1135755.4 Primal inf 29360.373 (313)
2829 Obj 1324229.3 Primal inf 14064.752 (197)
2952 Obj 1432668.8 Primal inf 4720.5706 (115)
3075 Obj 1455242 Primal inf 0.38744656 (6)
3081 Obj 1455243.4
Optimal - objective value 1455232.7
After Postsolve, objective 1455232.7, infeasibilities - dual 24.951498 (1), primal 3.1439549e-08 (1)
Presolved model was optimal, full model needs cleaning up
0 Obj 1455232.7 Dual inf 0.24951488 (1)
End of values pass after 2 iterations
2 Obj 1455232.7
Optimal - objective value 1455232.7
Optimal objective 1455232.678 - 3083 iterations time 0.362, Presolve 0.03
Total time (CPU seconds): 0.55 (Wallclock seconds): 0.52
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
INFO:linopy.model: Solve linear problem using Cbc solver
INFO:linopy.io:Writing objective.
Writing constraints.: 100%|██████████| 15/15 [00:00<00:00, 81.54it/s]
Writing continuous variables.: 100%|██████████| 7/7 [00:00<00:00, 249.67it/s]
INFO:linopy.io: Writing time: 0.23s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 9940 primals, 23828 duals
Objective: 2.65e+06
Solver model: not available
Solver message: Optimal - objective value 2649026.44753696
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Kirchhoff-Voltage-Law were not assigned to the network.
Welcome to the CBC MILP Solver
Version: 2.10.10
Build Date: Apr 19 2023
command line - cbc -printingOptions all -import /tmp/linopy-problem-35exxh_9.lp -solve -solu /tmp/linopy-solve-cig84kne.sol (default strategy 1)
Option for printingOptions changed from normal to all
Presolve 2394 (-21434) rows, 4363 (-5577) columns and 16355 (-28463) elements
Perturbing problem by 0.001% of 2240.9252 - largest nonzero change 0.00099928784 ( 0.0096128225%) - largest zero change 0.00099738508
0 Obj 97175.877 Primal inf 5191777.3 (2229) Dual inf 1060.2469 (4)
122 Obj 27996.104 Primal inf 3837028.4 (2185)
244 Obj 27996.104 Primal inf 3703917.1 (2140)
366 Obj 27996.104 Primal inf 3794398.3 (2104)
488 Obj 27996.886 Primal inf 3642563.8 (2069)
610 Obj 27997.418 Primal inf 4074601.5 (2030)
732 Obj 28002.037 Primal inf 2826288.1 (1959)
854 Obj 28004.075 Primal inf 3405656.8 (1876)
976 Obj 28007.342 Primal inf 5020913.6 (1812)
1098 Obj 28008.405 Primal inf 3962477.4 (1747)
1220 Obj 28011.557 Primal inf 17729335 (1668)
1342 Obj 28013.737 Primal inf 28156712 (1615)
1464 Obj 59475.288 Primal inf 40830396 (1518)
1586 Obj 59479.732 Primal inf 46727574 (1484)
1708 Obj 59484.206 Primal inf 50196311 (1341)
1830 Obj 59487.743 Primal inf 56271009 (1244)
1952 Obj 69450.068 Primal inf 8.6717468e+08 (1351)
2074 Obj 98637.852 Primal inf 8.7428539e+08 (1369)
2196 Obj 162067.47 Primal inf 5.0468364e+08 (1156)
2318 Obj 393247.1 Primal inf 5.0926048e+08 (1068)
2440 Obj 525582.07 Primal inf 6.8827228e+08 (1165)
2562 Obj 1056621.3 Primal inf 3.0632943e+08 (670)
2684 Obj 1503763 Primal inf 763236.57 (417)
2806 Obj 2113545.3 Primal inf 75204.548 (400)
2928 Obj 2389767.8 Primal inf 30784.149 (259)
3050 Obj 2532521.2 Primal inf 8989.4248 (175)
3172 Obj 2626120.3 Primal inf 5996.7813 (137)
3294 Obj 2648715.8 Primal inf 33.612269 (29)
3320 Obj 2649040.1
Optimal - objective value 2649026.4
After Postsolve, objective 2649026.4, infeasibilities - dual 124.09584 (3), primal 7.3815688e-07 (3)
Presolved model was optimal, full model needs cleaning up
0 Obj 2649026.4 Dual inf 1.2409581 (3)
End of values pass after 4 iterations
4 Obj 2649026.4
Optimal - objective value 2649026.4
Optimal objective 2649026.448 - 3324 iterations time 0.412, Presolve 0.02
Total time (CPU seconds): 0.61 (Wallclock seconds): 0.57
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
WARNING:pypsa.components:The following transformers have zero r, which could break the linear load flow:
Index(['2', '5', '10', '12', '13', '15', '18', '20', '22', '24', '26', '30',
'32', '37', '42', '46', '52', '56', '61', '68', '69', '74', '78', '86',
'87', '94', '95', '96', '99', '100', '104', '105', '106', '107', '117',
'120', '123', '124', '125', '128', '129', '138', '143', '156', '157',
'159', '160', '165', '184', '191', '195', '201', '220', '231', '232',
'233', '236', '247', '248', '250', '251', '252', '261', '263', '264',
'267', '272', '279', '281', '282', '292', '303', '307', '308', '312',
'315', '317', '322', '332', '334', '336', '338', '351', '353', '360',
'362', '382', '384', '385', '391', '403', '404', '413', '421', '450',
'458'],
dtype='object', name='Transformer')
INFO:linopy.model: Solve linear problem using Cbc solver
INFO:linopy.io:Writing objective.
Writing constraints.: 100%|██████████| 15/15 [00:00<00:00, 80.90it/s]
Writing continuous variables.: 100%|██████████| 7/7 [00:00<00:00, 251.83it/s]
INFO:linopy.io: Writing time: 0.23s
INFO:linopy.constants: Optimization successful:
Status: ok
Termination condition: optimal
Solution: 9940 primals, 23828 duals
Objective: 2.14e+06
Solver model: not available
Solver message: Optimal - objective value 2142956.88872811
INFO:pypsa.optimization.optimize:The shadow-prices of the constraints Kirchhoff-Voltage-Law were not assigned to the network.
Welcome to the CBC MILP Solver
Version: 2.10.10
Build Date: Apr 19 2023
command line - cbc -printingOptions all -import /tmp/linopy-problem-tly91uhn.lp -solve -solu /tmp/linopy-solve-3id285mx.sol (default strategy 1)
Option for printingOptions changed from normal to all
Presolve 2400 (-21428) rows, 4361 (-5579) columns and 16367 (-28451) elements
Perturbing problem by 0.001% of 6880.5027 - largest nonzero change 0.00098724516 ( 0.0042006337%) - largest zero change 0.00097642845
0 Obj 92706.97 Primal inf 5178889.1 (2227) Dual inf 2583.3603 (4)
123 Obj 23356.094 Primal inf 3897806.3 (2184)
246 Obj 23356.094 Primal inf 3592974.9 (2157)
369 Obj 23356.094 Primal inf 3689364.7 (2105)
492 Obj 23356.617 Primal inf 3579962.8 (2056)
615 Obj 23357.231 Primal inf 5364625.7 (2035)
738 Obj 23360.785 Primal inf 9121264.1 (1988)
861 Obj 23362.861 Primal inf 3526642.3 (1865)
984 Obj 23364.439 Primal inf 5539635.6 (1846)
1107 Obj 23365.598 Primal inf 4273554.4 (1749)
1230 Obj 23366.735 Primal inf 3991583.5 (1608)
1353 Obj 23368.187 Primal inf 3555483.7 (1512)
1476 Obj 40819.194 Primal inf 16632663 (1505)
1599 Obj 40820.659 Primal inf 22498717 (1579)
1722 Obj 40823.007 Primal inf 23240243 (1637)
1845 Obj 40825.072 Primal inf 10875948 (1280)
1968 Obj 41009.423 Primal inf 2411531.3 (1124)
2091 Obj 41234.773 Primal inf 3180208.6 (1017)
2214 Obj 41237.188 Primal inf 1264776.6 (851)
2337 Obj 66109.249 Primal inf 5097110.8 (999)
2460 Obj 421634.1 Primal inf 4254496.5 (816)
2583 Obj 1036119.8 Primal inf 144810.93 (431)
2706 Obj 1690865.1 Primal inf 26537.325 (342)
2829 Obj 1920365.2 Primal inf 10655.101 (214)
2952 Obj 2082573.4 Primal inf 5030.9035 (170)
3075 Obj 2130701.3 Primal inf 1569.5023 (96)
3198 Obj 2142584.3 Primal inf 32.942598 (28)
3241 Obj 2142962.3
Optimal - objective value 2142956.9
After Postsolve, objective 2142956.9, infeasibilities - dual 176.69321 (5), primal 1.4341023e-06 (5)
Presolved model was optimal, full model needs cleaning up
0 Obj 2142956.9 Dual inf 1.7669316 (5)
End of values pass after 6 iterations
6 Obj 2142956.9
Optimal - objective value 2142956.9
Optimal objective 2142956.889 - 3247 iterations time 0.382, Presolve 0.02
Total time (CPU seconds): 0.58 (Wallclock seconds): 0.55
[10]:
p_by_carrier = network.generators_t.p.groupby(network.generators.carrier, axis=1).sum()
p_by_carrier.drop(
(p_by_carrier.max()[p_by_carrier.max() < 1700.0]).index, axis=1, inplace=True
)
p_by_carrier.columns
[10]:
Index(['Brown Coal', 'Gas', 'Hard Coal', 'Nuclear', 'Run of River', 'Solar',
'Wind Offshore', 'Wind Onshore'],
dtype='object', name='carrier')
[11]:
colors = {
"Brown Coal": "brown",
"Hard Coal": "k",
"Nuclear": "r",
"Run of River": "green",
"Wind Onshore": "blue",
"Solar": "yellow",
"Wind Offshore": "cyan",
"Waste": "orange",
"Gas": "orange",
}
# reorder
cols = [
"Nuclear",
"Run of River",
"Brown Coal",
"Hard Coal",
"Gas",
"Wind Offshore",
"Wind Onshore",
"Solar",
]
p_by_carrier = p_by_carrier[cols]
[12]:
c = [colors[col] for col in p_by_carrier.columns]
fig, ax = plt.subplots(figsize=(12, 6))
(p_by_carrier / 1e3).plot(kind="area", ax=ax, linewidth=4, color=c, alpha=0.7)
ax.legend(ncol=4, loc="upper left")
ax.set_ylabel("GW")
ax.set_xlabel("")
fig.tight_layout()
[13]:
fig, ax = plt.subplots(figsize=(12, 6))
p_storage = network.storage_units_t.p.sum(axis=1)
state_of_charge = network.storage_units_t.state_of_charge.sum(axis=1)
p_storage.plot(label="Pumped hydro dispatch", ax=ax, linewidth=3)
state_of_charge.plot(label="State of charge", ax=ax, linewidth=3)
ax.legend()
ax.grid()
ax.set_ylabel("MWh")
ax.set_xlabel("")
fig.tight_layout()
[14]:
now = network.snapshots[4]
With the linear load flow, there is the following per unit loading:
[15]:
loading = network.lines_t.p0.loc[now] / network.lines.s_nom
loading.describe()
[15]:
count 852.000000
mean -0.002892
std 0.258575
min -0.700000
25% -0.129689
50% 0.003084
75% 0.122643
max 0.700000
dtype: float64
[16]:
fig, ax = plt.subplots(subplot_kw={"projection": ccrs.EqualEarth()}, figsize=(9, 9))
network.plot(
ax=ax,
line_colors=abs(loading),
line_cmap=plt.cm.jet,
title="Line loading",
bus_sizes=1e-3,
bus_alpha=0.7,
)
fig.tight_layout();
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.24.0/lib/python3.11/site-packages/cartopy/mpl/style.py:76: UserWarning: facecolor will have no effect as it has been defined as "never".
warnings.warn('facecolor will have no effect as it has been '
Let’s have a look at the marginal prices
[17]:
network.buses_t.marginal_price.loc[now].describe()
[17]:
count 585.000000
mean 15.737598
std 10.941995
min -10.397824
25% 6.992120
50% 15.841190
75% 25.048186
max 52.150120
Name: 2011-01-01 04:00:00, dtype: float64
[18]:
fig, ax = plt.subplots(subplot_kw={"projection": ccrs.PlateCarree()}, figsize=(8, 8))
plt.hexbin(
network.buses.x,
network.buses.y,
gridsize=20,
C=network.buses_t.marginal_price.loc[now],
cmap=plt.cm.jet,
zorder=3,
)
network.plot(ax=ax, line_widths=pd.Series(0.5, network.lines.index), bus_sizes=0)
cb = plt.colorbar(location="bottom")
cb.set_label("Locational Marginal Price (EUR/MWh)")
fig.tight_layout()
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.24.0/lib/python3.11/site-packages/cartopy/mpl/style.py:76: UserWarning: facecolor will have no effect as it has been defined as "never".
warnings.warn('facecolor will have no effect as it has been '
Curtailment variable#
By considering how much power is available and how much is generated, you can see what share is curtailed:
[19]:
carrier = "Wind Onshore"
capacity = network.generators.groupby("carrier").sum().at[carrier, "p_nom"]
p_available = network.generators_t.p_max_pu.multiply(network.generators["p_nom"])
p_available_by_carrier = p_available.groupby(network.generators.carrier, axis=1).sum()
p_curtailed_by_carrier = p_available_by_carrier - p_by_carrier
[20]:
p_df = pd.DataFrame(
{
carrier + " available": p_available_by_carrier[carrier],
carrier + " dispatched": p_by_carrier[carrier],
carrier + " curtailed": p_curtailed_by_carrier[carrier],
}
)
p_df[carrier + " capacity"] = capacity
[21]:
p_df["Wind Onshore curtailed"][p_df["Wind Onshore curtailed"] < 0.0] = 0.0
[22]:
fig, ax = plt.subplots(figsize=(10, 4))
p_df[[carrier + " dispatched", carrier + " curtailed"]].plot(
kind="area", ax=ax, linewidth=3
)
p_df[[carrier + " available", carrier + " capacity"]].plot(ax=ax, linewidth=3)
ax.set_xlabel("")
ax.set_ylabel("Power [MW]")
ax.set_ylim([0, 40000])
ax.legend()
fig.tight_layout()
Non-Linear Power Flow#
Now perform a full Newton-Raphson power flow on the first hour. For the PF, set the P to the optimised P.
[23]:
network.generators_t.p_set = network.generators_t.p
network.storage_units_t.p_set = network.storage_units_t.p
Set all buses to PV, since we don’t know what Q set points are
[24]:
network.generators.control = "PV"
# Need some PQ buses so that Jacobian doesn't break
f = network.generators[network.generators.bus == "492"]
network.generators.loc[f.index, "control"] = "PQ"
Now, perform the non-linear PF.
[25]:
info = network.pf();
INFO:pypsa.pf:Performing non-linear load-flow on AC sub-network SubNetwork 0 for snapshots DatetimeIndex(['2011-01-01 00:00:00', '2011-01-01 01:00:00',
'2011-01-01 02:00:00', '2011-01-01 03:00:00',
'2011-01-01 04:00:00', '2011-01-01 05:00:00',
'2011-01-01 06:00:00', '2011-01-01 07:00:00',
'2011-01-01 08:00:00', '2011-01-01 09:00:00',
'2011-01-01 10:00:00', '2011-01-01 11:00:00',
'2011-01-01 12:00:00', '2011-01-01 13:00:00',
'2011-01-01 14:00:00', '2011-01-01 15:00:00',
'2011-01-01 16:00:00', '2011-01-01 17:00:00',
'2011-01-01 18:00:00', '2011-01-01 19:00:00',
'2011-01-01 20:00:00', '2011-01-01 21:00:00',
'2011-01-01 22:00:00', '2011-01-01 23:00:00'],
dtype='datetime64[ns]', name='snapshot', freq=None)
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044446 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044481 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.043828 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.043849 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044255 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044086 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044562 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044068 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044169 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.043838 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044449 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044546 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044386 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044942 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.043778 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.043801 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044272 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.045208 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044738 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044319 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044060 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044168 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.044939 seconds
INFO:pypsa.pf:Newton-Raphson solved in 4 iterations with error of 0.000000 in 0.043816 seconds
Any failed to converge?
[26]:
(~info.converged).any().any()
[26]:
False
With the non-linear load flow, there is the following per unit loading of the full thermal rating.
[27]:
(network.lines_t.p0.loc[now] / network.lines.s_nom).describe()
[27]:
count 852.000000
mean 0.000434
std 0.260926
min -0.813358
25% -0.125478
50% 0.003032
75% 0.126695
max 0.827178
dtype: float64
Let’s inspect the voltage angle differences across the lines have (in degrees)
[28]:
df = network.lines.copy()
for b in ["bus0", "bus1"]:
df = pd.merge(
df, network.buses_t.v_ang.loc[[now]].T, how="left", left_on=b, right_index=True
)
s = df[str(now) + "_x"] - df[str(now) + "_y"]
(s * 180 / np.pi).describe()
[28]:
count 852.000000
mean -0.022840
std 2.373703
min -12.158621
25% -0.463026
50% 0.001586
75% 0.537443
max 17.959258
dtype: float64
Plot the reactive power
[29]:
fig, ax = plt.subplots(subplot_kw={"projection": ccrs.EqualEarth()}, figsize=(9, 9))
q = network.buses_t.q.loc[now]
bus_colors = pd.Series("r", network.buses.index)
bus_colors[q < 0.0] = "b"
network.plot(
bus_sizes=1e-4 * abs(q),
ax=ax,
bus_colors=bus_colors,
title="Reactive power feed-in (red=+ve, blue=-ve)",
);
/home/docs/checkouts/readthedocs.org/user_builds/pypsa/conda/v0.24.0/lib/python3.11/site-packages/cartopy/mpl/style.py:76: UserWarning: facecolor will have no effect as it has been defined as "never".
warnings.warn('facecolor will have no effect as it has been '