Meshed AC-DC Networks¶
This example demonstrates how to optimise meshed AC-DC networks in PyPSA. The example has a 3-node AC network coupled via AC-DC converters to a 3-node DC network. There is also a single point-to-point DC connection using the Link component.
import pypsa
n = pypsa.examples.ac_dc_meshed()
n.links.loc["Norwich Converter", "p_nom_extendable"] = False
line_color = n.lines.bus0.map(n.buses.carrier).map(
lambda ct: "r" if ct == "DC" else "b"
)
n.plot(
line_color=line_color,
link_color="c",
title="AC (blue) - DC (red) - P2P-DC (cyan)",
jitter=0.4,
)
We inspect the topology of the network. Therefore, use n.determine_network_topology() and inspect the subnetworks in n.sub_networks.
n.determine_network_topology()
n.sub_networks["n_branches"] = [len(sn.branches()) for sn in n.sub_networks.obj]
n.sub_networks["n_buses"] = [
len(sn.components.buses.static) for sn in n.sub_networks.obj
]
n.sub_networks
The network covers 10 time steps. These are given by the snapshots attribute.
n.snapshots
There are 6 generators in the network, 3 wind and 3 gas. All are attached to AC buses:
n.generators
We see that the generators have different capital and marginal costs. All of them have a p_nom_extendable set to True, meaning that capacities can be extended in the optimisation. The wind generators have a per unit limit for each time step, given by the weather potentials at the site.
n.generators_t.p_max_pu.plot()
Alright now we know how the network looks like, where the generators and lines are. Now, let's perform a optimization of the operation and capacities.
n.optimize();
The objective is given by:
n.objective
Why is this number negative? It considers the starting point of the optimisation, thus the existent capacities given by n.generators.p_nom are taken into account.
The real system cost are given by
n.objective + n.objective_constant
The optimal capacities are given by p_nom_opt for generators, links and storages and s_nom_opt for lines.
Let's look how the optimal capacities for the generators look like.
n.generators.p_nom_opt.div(1e3).round(2).sort_values()
Their production is again given as a time-series in n.generators_t.
n.generators_t.p.div(1e3).plot.area(stacked=True, lw=0, ylabel="GW")
What are the locational marginal prices in the network? From the optimisation these are given for each bus and snapshot.
n.buses_t.marginal_price.mean(axis=1).plot(figsize=(8, 3), ylabel="€/MWh")
We can inspect further quantities as the active power of AC-DC converters and HVDC link.
n.links_t.p0.round(2)
n.lines_t.p0.round(2)
...or the active power injection per bus.
n.buses_t.p.round(2)