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 https://github.com/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:

  1. Rough approximations have been made for missing grid data, e.g. 220kV-380kV transformers and connections between close sub-stations missing from OSM.

  2. 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.

  3. Attaching power plants to the nearest high voltage substation may not reflect reality.

  4. 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).

  5. The borders and neighbouring countries are not represented.

  6. Hydroelectric power stations are not modelled accurately.

  7. The marginal costs are illustrative, not accurate.

  8. 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.

  9. 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).

  10. Biomass from the EEG Stammdaten are not read in at the moment.

  11. 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
%matplotlib inline
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
/tmp/ipykernel_735/547834826.py in <module>
      4 import os
      5 import matplotlib.pyplot as plt
----> 6 import cartopy.crs as ccrs
      7 get_ipython().run_line_magic('matplotlib', 'inline')

ModuleNotFoundError: No module named 'cartopy'
[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

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");
fig.tight_layout()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/1083410289.py in <module>
----> 1 fig,ax = plt.subplots(1,1,subplot_kw={"projection":ccrs.EqualEarth()}, figsize=(8,8))
      2
      3 load_distribution = (network.loads_t.p_set.loc[network.snapshots[0]]
      4                      .groupby(network.loads.bus).sum())
      5 network.plot(bus_sizes=1e-5*load_distribution, ax=ax, title="Load distribution");

NameError: name 'ccrs' is not defined
[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.)
    network.plot(ax=ax,bus_sizes=2e-5*gen_distribution)
    ax.set_title(tech)
fig.tight_layout()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/2925664976.py in <module>
      9
     10
---> 11 fig, axes = plt.subplots(nrows=n_rows, ncols=n_cols, subplot_kw={"projection":ccrs.EqualEarth()})
     12 size = 6
     13 fig.set_size_inches(size*n_cols,size*n_rows)

NameError: name 'ccrs' is not defined

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.

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.lopf(network.snapshots[group_size*i:group_size*i+group_size], solver_name='cbc',
                pyomo=False)
INFO:pypsa.linopf:Prepare linear problem
INFO:pypsa.linopf:Total preparation time: 1.57s
INFO:pypsa.linopf:Solve linear problem using Cbc solver
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/tmp/ipykernel_735/188707333.py in <module>
      8             network.storage_units_t.state_of_charge.loc[network.snapshots[group_size*i-1]])
      9     network.lopf(network.snapshots[group_size*i:group_size*i+group_size], solver_name='cbc',
---> 10                 pyomo=False)

~/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)
    648             return network_lopf(self, **args)
    649         else:
--> 650             return network_lopf_lowmem(self, **args)
    651
    652

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/linopf.py in network_lopf(n, snapshots, solver_name, solver_logfile, extra_functionality, multi_investment_periods, skip_objective, skip_pre, extra_postprocessing, formulation, keep_references, keep_files, keep_shadowprices, solver_options, warmstart, store_basis, solver_dir)
   1209     solve = eval(f'run_and_read_{solver_name}')
   1210     res = solve(n, problem_fn, solution_fn, solver_logfile,
-> 1211                 solver_options, warmstart, store_basis)
   1212
   1213     status, termination_condition, variables_sol, constraints_dual, obj = res

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pypsa/linopt.py in run_and_read_cbc(n, problem_fn, solution_fn, solver_logfile, solver_options, warmstart, store_basis)
    626
    627     log = open(solver_logfile, 'w') if solver_logfile is not None else subprocess.PIPE
--> 628     result = subprocess.Popen(command.split(' '), stdout=log)
    629     result.wait()
    630

~/.pyenv/versions/3.7.9/lib/python3.7/subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors, text)
    798                                 c2pread, c2pwrite,
    799                                 errread, errwrite,
--> 800                                 restore_signals, start_new_session)
    801         except:
    802             # Cleanup if the child failed starting.

~/.pyenv/versions/3.7.9/lib/python3.7/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
   1549                         if errno_num == errno.ENOENT:
   1550                             err_msg += ': ' + repr(err_filename)
-> 1551                     raise child_exception_type(errno_num, err_msg, err_filename)
   1552                 raise child_exception_type(err_msg)
   1553

FileNotFoundError: [Errno 2] No such file or directory: 'cbc': 'cbc'
[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.]).index,axis=1,inplace=True)
p_by_carrier.columns
[10]:
Index([], 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]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/tmp/ipykernel_735/3736027954.py in <module>
     10 #reorder
     11 cols = ["Nuclear","Run of River","Brown Coal","Hard Coal","Gas","Wind Offshore","Wind Onshore","Solar"]
---> 12 p_by_carrier = p_by_carrier[cols]

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/core/frame.py in __getitem__(self, key)
   3462             if is_iterator(key):
   3463                 key = list(key)
-> 3464             indexer = self.loc._get_listlike_indexer(key, axis=1)[1]
   3465
   3466         # take() does not accept boolean indexers

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/core/indexing.py in _get_listlike_indexer(self, key, axis)
   1312             keyarr, indexer, new_indexer = ax._reindex_non_unique(keyarr)
   1313
-> 1314         self._validate_read_indexer(keyarr, indexer, axis)
   1315
   1316         if needs_i8_conversion(ax.dtype) or isinstance(

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/core/indexing.py in _validate_read_indexer(self, key, indexer, axis)
   1372                 if use_interval_msg:
   1373                     key = list(key)
-> 1374                 raise KeyError(f"None of [{key}] are in the [{axis_name}]")
   1375
   1376             not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique())

KeyError: "None of [Index(['Nuclear', 'Run of River', 'Brown Coal', 'Hard Coal', 'Gas',\n       'Wind Offshore', 'Wind Onshore', 'Solar'],\n      dtype='object', name='carrier')] are in the [columns]"
[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=.7)
ax.legend(ncol=4,loc="upper left")
ax.set_ylabel("GW")
ax.set_xlabel("")
fig.tight_layout()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_735/931052594.py in <module>
      2
      3 fig, ax = plt.subplots(figsize=(12, 6))
----> 4 (p_by_carrier/1e3).plot(kind="area", ax=ax, linewidth=4, color=c, alpha=.7)
      5 ax.legend(ncol=4,loc="upper left")
      6 ax.set_ylabel("GW")

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/plotting/_core.py in __call__(self, *args, **kwargs)
    970                     data.columns = label_name
    971
--> 972         return plot_backend.plot(data, kind=kind, **kwargs)
    973
    974     __call__.__doc__ = __doc__

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/plotting/_matplotlib/__init__.py in plot(data, kind, **kwargs)
     69             kwargs["ax"] = getattr(ax, "left_ax", ax)
     70     plot_obj = PLOT_CLASSES[kind](data, **kwargs)
---> 71     plot_obj.generate()
     72     plot_obj.draw()
     73     return plot_obj.result

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/plotting/_matplotlib/core.py in generate(self)
    284     def generate(self):
    285         self._args_adjust()
--> 286         self._compute_plot_data()
    287         self._setup_subplots()
    288         self._make_plot()

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/plotting/_matplotlib/core.py in _compute_plot_data(self)
    451         # no non-numeric frames or series allowed
    452         if is_empty:
--> 453             raise TypeError("no numeric data to plot")
    454
    455         self.data = numeric_data.apply(self._convert_to_ndarray)

TypeError: no numeric data to plot
../_images/examples_scigrid-lopf-then-pf_16_1.png
[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()
../_images/examples_scigrid-lopf-then-pf_17_0.png
[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    0.0
mean     NaN
std      NaN
min      NaN
25%      NaN
50%      NaN
75%      NaN
max      NaN
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=.7)
fig.tight_layout();
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/2567390097.py in <module>
----> 1 fig, ax = plt.subplots(subplot_kw={"projection":ccrs.EqualEarth()}, figsize=(9,9))
      2 network.plot(ax=ax, line_colors=abs(loading), line_cmap=plt.cm.jet, title="Line loading",
      3             bus_sizes=1e-3, bus_alpha=.7)
      4 fig.tight_layout();

NameError: name 'ccrs' is not defined

Let’s have a look at the marginal prices

[17]:
network.buses_t.marginal_price.loc[now].describe()
[17]:
count    0.0
mean     NaN
std      NaN
min      NaN
25%      NaN
50%      NaN
75%      NaN
max      NaN
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()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/3356461026.py in <module>
----> 1 fig, ax = plt.subplots(subplot_kw={"projection":ccrs.PlateCarree()}, figsize=(8,8))
      2
      3 plt.hexbin(network.buses.x, network.buses.y,
      4            gridsize=20,
      5            C=network.buses_t.marginal_price.loc[now],

NameError: name 'ccrs' is not defined

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
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)
   3360             try:
-> 3361                 return self._engine.get_loc(casted_key)
   3362             except KeyError as err:

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()

pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()

pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()

KeyError: 'Wind Onshore'

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
/tmp/ipykernel_735/325685992.py in <module>
      1 p_df = pd.DataFrame({carrier + " available" : p_available_by_carrier[carrier],
----> 2                      carrier + " dispatched" : p_by_carrier[carrier],
      3                      carrier + " curtailed" : p_curtailed_by_carrier[carrier]})
      4
      5 p_df[carrier + " capacity"] = capacity

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/core/frame.py in __getitem__(self, key)
   3456             if self.columns.nlevels > 1:
   3457                 return self._getitem_multilevel(key)
-> 3458             indexer = self.columns.get_loc(key)
   3459             if is_integer(indexer):
   3460                 indexer = [indexer]

~/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)
   3361                 return self._engine.get_loc(casted_key)
   3362             except KeyError as err:
-> 3363                 raise KeyError(key) from err
   3364
   3365         if is_scalar(key) and isna(key) and not self.hasnans:

KeyError: 'Wind Onshore'
[21]:
p_df["Wind Onshore curtailed"][p_df["Wind Onshore curtailed"] < 0.] = 0.
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/1350209615.py in <module>
----> 1 p_df["Wind Onshore curtailed"][p_df["Wind Onshore curtailed"] < 0.] = 0.

NameError: name 'p_df' is not defined
[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()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/1018666379.py in <module>
      1 fig,ax = plt.subplots(figsize=(10,4))
----> 2 p_df[[carrier + " dispatched",carrier + " curtailed"]].plot(kind="area",ax=ax,linewidth=3)
      3 p_df[[carrier + " available",carrier + " capacity"]].plot(ax=ax,linewidth=3)
      4
      5 ax.set_xlabel("")

NameError: name 'p_df' is not defined
../_images/examples_scigrid-lopf-then-pf_29_1.png

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)
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 4462170395869686666558565213598346597367808.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 4462170395869686666558565213598346597367808.000000 in 1.145045 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 64134244997438141169384069509718827026559795200.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 64134244997438141169384069509718827026559795200.000000 in 1.144177 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 7124464791618362981636326697192099319644160.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 7124464791618362981636326697192099319644160.000000 in 1.144293 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 25933004325100727718288638218066445991936.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 25933004325100727718288638218066445991936.000000 in 1.147570 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 95536054709905356593441708233250185513741058048.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 95536054709905356593441708233250185513741058048.000000 in 1.146171 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 10213224735855876597221874147744883079324368896.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 10213224735855876597221874147744883079324368896.000000 in 1.144740 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 4409113754790097222376491247628452343316480.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 4409113754790097222376491247628452343316480.000000 in 1.143575 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 6067641330343037652249432641994998239199232.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 6067641330343037652249432641994998239199232.000000 in 1.140286 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 39638783082767799404133996182243125292433408.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 39638783082767799404133996182243125292433408.000000 in 1.143961 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 836427823007647932933329322497408847839232.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 836427823007647932933329322497408847839232.000000 in 1.146977 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 71706505541934613698356507078171917608288256.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 71706505541934613698356507078171917608288256.000000 in 1.142601 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 21881335020045032925387480594694390029484032.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 21881335020045032925387480594694390029484032.000000 in 1.142812 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 1309307710309007244087343022971791574302720.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 1309307710309007244087343022971791574302720.000000 in 1.154400 seconds
/home/docs/checkouts/readthedocs.org/user_builds/pypsa-docs-staging/envs/latest/lib/python3.7/site-packages/scipy/sparse/linalg/dsolve/linsolve.py:206: MatrixRankWarning: Matrix is exactly singular
  warn("Matrix is exactly singular", MatrixRankWarning)
INFO:pypsa.pf:Newton-Raphson solved in 81 iterations with error of nan in 0.927283 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 12603350923603283872822752616710539371872256.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 12603350923603283872822752616710539371872256.000000 in 1.143045 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 226356600533306534311359341421140620785745920.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 226356600533306534311359341421140620785745920.000000 in 1.147439 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 5018447704701696270421124301132578175320064.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 5018447704701696270421124301132578175320064.000000 in 1.145536 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 2793766655037082414876002172957460992622592.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 2793766655037082414876002172957460992622592.000000 in 1.144317 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 4095108658505860507572837512462831053701120.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 4095108658505860507572837512462831053701120.000000 in 1.144553 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 20408559067215906097796429047756779959959420928.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 20408559067215906097796429047756779959959420928.000000 in 1.144528 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 279944836215083537867063818173437628201920626688.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 279944836215083537867063818173437628201920626688.000000 in 1.145147 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 289068161696273600109183177713543857307648.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 289068161696273600109183177713543857307648.000000 in 1.155288 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 82144127194000197214594311283881070380269436928.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 82144127194000197214594311283881070380269436928.000000 in 1.146463 seconds
WARNING:pypsa.pf:Warning, we didn't reach the required tolerance within 100 iterations, error is at 421757405219753153981710327545690201645907968.000000. See the section "Troubleshooting" in the documentation for tips to fix this.
INFO:pypsa.pf:Newton-Raphson solved in 100 iterations with error of 421757405219753153981710327545690201645907968.000000 in 1.144910 seconds

Any failed to converge?

[26]:
(~info.converged).any().any()
[26]:
True

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    8.520000e+02
mean     3.901772e+39
std      6.603747e+40
min     -2.357971e+41
25%     -5.966009e-01
50%      1.530693e+00
75%      3.809793e+14
max      1.302964e+42
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    8.520000e+02
mean     4.301934e+16
std      6.793176e+17
min     -7.641172e+18
25%     -1.027632e+05
50%      0.000000e+00
75%      2.497523e+05
max      4.114836e+18
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.] = "b"

network.plot(bus_sizes=1e-4*abs(q),ax=ax,bus_colors=bus_colors,
             title="Reactive power feed-in (red=+ve, blue=-ve)");
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/tmp/ipykernel_735/3983992349.py in <module>
----> 1 fig,ax = plt.subplots(subplot_kw={"projection":ccrs.EqualEarth()}, figsize=(9,9))
      2
      3 q = network.buses_t.q.loc[now]
      4 bus_colors = pd.Series("r",network.buses.index)
      5 bus_colors[q< 0.] = "b"

NameError: name 'ccrs' is not defined