Python for Power System Analysis (PyPSA) is a free software toolbox for simulating and optimising modern electrical power systems over multiple periods. PyPSA includes models for conventional generators with unit commitment, variable renewable generation, storage units, coupling to other energy sectors, and mixed alternating and direct current networks. It is designed to be easily extensible and to scale well with large networks and long time series. In this paper the basic functionality of PyPSA is described, including the formulation of the full power flow equations and the multi-period optimisation of operation and investment with linear power flow equations. PyPSA is positioned in the existing free software landscape as a bridge between traditional power flow analysis tools for steady-state analysis and full multi-period energy system models. The functionality is demonstrated on two open datasets of the transmission system in Germany (based on SciGRID) and Europe (based on GridKit).

Power system tools model the interactions between the electrical grid and the consumers and generators which use the grid. The importance of software modelling of the grid has risen in recent years given the increase in distributed and fluctuating wind and solar generation, and the increasing electrification of all energy demand. On the generation side, variable renewable generation causes loading in parts of the grid where it was never expected, and introduces new stochastic influences on the flow patterns. On the demand side, the need to decarbonise the transport and heating sectors is leading to the electrification of these sectors and hence higher electrical demand, replacing internal combustion engines with electric motors in the transport sector, and replacing fossil fuel boilers with heat pumps, resistive heaters and cogeneration for low-temperature space and water heating. In addition, the increasing deployment of storage technologies introduces many network users which are both consumers and generators of energy.

The increasing complexity of the electricity system requires new tools for power system modelling. Many of the tools currently used for power system modelling were written in the era before widespread integration of renewable energy and the electrification of transport and heating. They therefore typically focus on network flows in single time periods. Examples of such tools include commercial products like DIgSILENT PowerFactory [

The consideration of multiple time periods is important on the operational side for unit commitment of conventional generators and the optimisation of storage and demand side management, and on the investment side for optimising infrastructure capacities over representative load and weather situations. Several tools have subsets of these capabilities, such as calliope [

Python for Power System Analysis (PyPSA), the tool presented in this paper, was developed at the Frankfurt Institute for Advanced Studies to bridge the gap between power system analysis software and general energy system modelling tools. PyPSA can model the operation and optimal investment of the energy system over multiple periods. It has models for the unit commitment of conventional generators, time-varying renewable generators, storage units, all combinations of direct and alternating current electricity networks, and the coupling of electricity to other energy sectors, such as gas, heating and transport. It can perform full load flow calculations and linearised optimal load flow, including under consideration of security constraints. It was written from the start with variable renewables, storage and sector-coupling in mind, so that it performs well with large networks and long time series.

Given the complexity of power system tools and the different needs of different users, it is crucial that such tools are both transparent in what they do and easily extendable by the user. To this end, PyPSA was released as free software under the GNU General Public Licence Version 3 (GPLv3) [

PyPSA is available online in the Python Package Index (PyPI), on GitHub [

This paper describes version 0.11.0 of PyPSA [

In this section the basic components, power flow, linear optimal power flow, energy system optimisation, unit commitment, contingency modelling and other functionality of PyPSA are described. The definitions of the main variables used in this section can be found in Table

Nomenclature.

Variable | Units | Definition |
---|---|---|

Bus labels | ||

Generator energy carrier labels (e.g. wind, solar, gas, etc.) | ||

Storage energy carrier labels (e.g. battery, hydrogen, etc.) | ||

Branch labels | ||

Cycle labels | ||

Snapshot/time point labels | ||

_{r/s} |
tCO_{2}eq/MWh_{th} |
CO_{2}-equivalent emissions of energy carrier |

_{t} |
h | Weighting of snapshot in objective function |

_{n,r,t} |
MW | Dispatch of generator at bus |

_{n,r} |
MW | Power capacity of generator |

_{n,r,t} |
MW/MW | Power availability per unit of generator capacity |

_{n,r} |
MW_{el}/MW_{th} |
Efficiency of generator |

_{n,r,t} |
On/off binary status for generator unit commitment | |

h | Generator minimum down time | |

h | Generator minimum up time | |

_{n,r} |
(MW/MW)/h | Generator ramp up limit per unit of capacity |

_{n,r} |
(MW/MW)/h | Generator ramp down limit per unit of capacity |

_{n,r} |
€/MW | Generator capital (fixed) cost |

_{n,r} |
€/MWh | Generator operating (variable) cost |

_{n,r(,t)} |
€ | Generator start up cost (in time |

_{n,r(,t)} |
€ | Generator shut down cost (in time |

_{n,s,t} |
MW | Dispatch of storage at bus |

_{n,s} |
MW | Power capacity of storage |

_{n,s,t} |
MWh | Storage state of charge (energy level) |

_{n,s} |
MWh | Storage energy capacity |

_{n,s} |
€/MW | Storage power capacity cost |

_{n,s} |
€/MWh | Storage energy capacity cost |

_{n,s} |
€/MWh | Storage dispatch cost |

_{n,t} |
MW | Electrical load at bus |

_{n,t} |
€/MWh | Marginal price at bus |

_{n} |
kV | Complex voltage at bus |

_{n} |
rad | Voltage angle at bus |

_{n} |
kA | Complex current at bus |

_{n} |
MW | Total active power injection at bus |

_{n} |
MVAr | Total reactive power injection at bus |

_{n} |
MVA | Total apparent power injection at bus |

_{ℓ,t} |
MW | Branch active power flow |

_{ℓ} |
MW | Branch active power rating |

_{ℓ} |
€/MW | Branch capital cost |

_{ℓ} |
Ω | Branch series reactance |

_{ℓ} |
Ω | Branch series resistance |

Variable | Units | Definition |

_{ℓ} |
Ω | Branch series impedance |

_{ℓ} |
S | Branch shunt admittance |

_{ℓ} |
Transformer tap ratio | |

rad | Transformer phase shift | |

_{ℓ,t} |
MW/MW | Efficiency loss of a link |

_{nℓ} |
||

_{ℓ}_{c} |
||

_{nm} |
S | Bus admittance matrix |

_{ℓ}_{k} |
S | Diagonal |

_{ℓ}_{k} |
Branch Outage Distribution Factor |

PyPSA’s representation of the power system is built by connecting the components listed in Table

PyPSA components.

Network | Container for all other network components. |

Bus | Fundamental nodes to which all other components attach. |

Carrier | Energy carrier (e.g. wind, solar, gas, etc.). |

Load | A consumer of energy. |

Generator | Generator whose feed-in can be flexible subject to minimum loading or minimum down and up times, or variable according to a given time series of power availability. |

Storage Unit | A device which can shift energy from one time to another, subject to efficiency losses. |

Store | A more fundamental storage object with no restrictions on charging or discharging power. |

Shunt Impedance | An impedance in shunt to a bus. |

Line | A branch which connects two buses of the same voltage. |

Transformer | A branch which connects two buses of different voltages. |

Link | A branch with a controllable power flow between two buses. |

Buses are the fundamental nodes to which all other components attach. Their mathematical role is to enforce energy conservation at the bus at all times (essentially Kirchhoff’s Current Law).

Loads, generators, storage units, stores and shunt impedances attach to a single bus and determine the power balance at the bus. Loads represent a fixed power demand; a generator’s dispatch can be optimised within its power availaiblity; stores can shift power from one time to another with a standing loss efficiency for energy leakage; storage units behave like stores, but they can also have efficiency losses and power limits upon charging and discharging; finally shunt impedances have a voltage-dependent power consumption.

Lines and transformers connect two buses with a given impedance. Power flows through lines and transformers according to the power imbalances at the buses and the impedances in the network. Lines and transformers are referred to collectively as ‘passive branches’ to distinguish them from controllable link branches. The impedances of the passive branches are modeled internally using the equivalent PI model. The relation between the series impedance ^{shift}, and the complex currents _{0}, _{1} and complex voltages _{0}, _{1} at the buses labelled 0 and 1 is given by

(For lines, for which neither the tap ratio or the phase shift are relevant, set ^{shift} = 0 in this equation.) The equivalent circuit is shown in Figure

Electrical property definitions for passive branches (lines and transformers).

Links connect two buses with a controllable active power dispatch that can be set by the user or optimised by PyPSA. Links can be used to represent point-to-point high voltage direct current (HVDC) lines, import-export capacities in transport models such as Net-Transfer-Capacity (NTC) models, or general energy conversion processes with a given efficiency, such as resistive heaters or heat pumps (from electricity to heat) or gas boilers (from gas to heat). Their efficiency can also be time-varying (e.g. to represent the ambient temperature dependence of a heat pump’s coefficient of performance). Networks of links implement Kirchoff’s Current Law (energy conservation at each bus), but not Kirchoff’s Voltage Law, which is obeyed by networks of passive branches.

A generator can also be represented in terms of more basic components: a bus is added for the fuel source with a store to represent the amount of fuel available. It is then connected to the electricity bus with a link to represent the energy conversion loss. Similarly a storage unit can be represented with an additional bus for the storage medium with a store attached, and then two links connected to the electricity bus to represent charging and discharging.

Energy enters the model in generators; in storage units or stores with higher energy levels before than after the simulation; and in any components with efficiency greater than 1 (such as heat pumps). Energy leaves the model in loads; in storage units or stores with higher energy levels after than before the simulation; and in lines, links or storage units with efficiency less than 1.

In a power flow calculation, the user specifies the power dispatch of all dispatchable components (loads, generators, storage units, stores and links) and then PyPSA computes the resulting voltages in the network and hence the power flows in passive branches (lines and transformers) based on their impedances.

A power flow calculation for an alternating current (AC) network ensures that for all buses labelled by

where _{n}_{n}_{n}_{n}_{nm}

The inputs and outputs for the buses are given as follows:

For the chosen slack bus _{0}| and the voltage angle _{0} are given. PyPSA must find the powers _{0} and _{0}.

For _{n}_{n}_{n}_{n}

For _{n}_{n}_{n}_{n}

The non-linear equation system (2) is then solved using the Newton-Raphson algorithm [_{n}_{0} and |_{n}

A power flow calculation for a direct current (DC) network ensures that for all buses labelled by

where _{n}_{ij}

In some circumstances a linearisation of the AC power flow equations (2) can provide a good approximation to the full non-linear solution [

In this case it can be shown [

where _{ℓ}_{ℓ}^{T}

For DC networks the equation (3) is linearised by positing _{n}_{n}_{n}_{n}_{n}_{ℓ}_{ℓ}

PyPSA is a partial equilibrium model that can optimise both short-term operation and long-term investment in the energy system as a linear problem using the linear power flow equations.

PyPSA minimises total system costs, which include the variable and fixed costs of generation, storage and transmission, given technical and physical constraints. The objective function is given by

It consists of the branch capacities _{ℓ}_{ℓ}_{n,r}_{n,r}_{n,r,t}_{n,r}_{n,r,t}_{n,r,t}_{n,s}_{n,s}_{n,s}_{n,s}_{n,s,t}^{+} and the associated variable costs _{n,s}_{ℓ,t}_{t}_{t} w_{t}

The dispatch of generators _{n,r,t}_{n,r}_{n,r,t}_{n,r,t}_{n,r}

For conventional generators the availabilities are usually constant; a fully flexible generator would have _{n,r,t}_{n,r,t}_{n,r,t}_{n,r,t}

The dispatch can also be limited by ramp rate constraints _{n,r}_{n,r}

Unit commitment for conventional generators is described in Section 2.5.

The power capacity _{n,r}_{n,r}_{n,r}

The dispatch of storage units _{n,s,t}

except _{n,s,t}_{n,s}

The energy levels _{n,s,t}_{n,s}

Positive and negative parts of a value are denoted as [·]^{+} = max(·, 0), [·]^{–} = –min(·, 0). The storage units can have a standing loss (self-discharging leakage rate) _{n,s,0}, a charging efficiency _{n,s,+}, a discharging efficiency _{n,s,–}, inflow (e.g. river inflow in a reservoir) and spillage. The initial energy level can be set by the user, or it is assumed to be cyclic, i.e. _{n,s,t}_{=0} = _{n,s,t=T}

The store component is a more basic version of the storage unit: its charging and discharging power cannot be limited and there are no charging and discharging efficiencies _{n,s,+}, _{n,s,–}. The energy levels of the store can also be restricted by time series _{n,s,t}, ē_{n,s,t}_{n,s}_{n,s}

Global constraints related to primary energy consumption, such as emission limits, can also be implemented. For example, CO_{2} emissions can be limited by a cap CAP_{CO}_{2}, implemented using the specific emissions _{r}_{2}_{th} of the fuel _{n,r}

_{CO2} is the shadow price of this constraint.

The (inelastic) electricity demand _{n,t}_{ℓ,t}

where _{ℓ,n,t}_{ℓ,n,t}_{ℓ,n,t}_{ℓ,t}_{ℓ,n,t}_{ℓ,n,t}_{nℓ}_{ℓ,t}_{n,t}

The flows in all passive branches are constrained by their capacities _{ℓ}

For links, the flows can be more finely controlled with time-dependent per unit availabilities

which allows, for example, time-dependent demand-side management schemes to be modelled [

The flows in links are fully controllable.

Power flows in networks of passive branches (lines and transformers) according to the linear power flow equations. It is assumed that the network is lossless, so that _{ℓ,n,t}_{ℓc}

where _{ℓ}

Since branch capacities _{ℓ}_{ℓ}_{ℓ}_{ℓ,t}_{ℓ}

PyPSA can also optimise operation and investment in other energy sectors, such as natural gas, heating and transport. These sectors can be modelled using a network of links with efficiencies for energy conversion losses; an example from a recent paper [

Example of the coupling in PyPSA between electricity (at top) and other energy sectors: transport, hydrogen, natural gas and heating. There is a bus for each energy carrier, to which different loads, energy sources and converters are attached.

Unit commitment can be turned on for any generator. This introduces a times series of new binary status variables _{n,r,t}

so that if _{n,r,t}_{n,r,t}

If

(i.e. if the generator has just started up (_{n,r,t}_{n,r,t}_{–1} = 1) then it has to run for at least

For non-zero start up costs _{n,r}_{n,r,t}

so that it is only non-zero if _{n,r,t}_{n,r,t}_{–1} = 1, i.e. the generator has just started, in which case the inequality is saturated _{n,r,t}_{n,r}_{n,r,t}

The ramp-rate limits in equation (7) can also be suplemented by ramping limits at start-up and shut-down.

PyPSA has functionality to examine the steady state of the power system after outages of passive branches, based on an analysis of the linear power flow.

PyPSA calculates the Branch Outage Distribution Factor (BODF) from the Power Transfer Distribution Factors (PTDF) (see [

Here _{ℓ}

The BODF can then be used in Security-Constrained Linear Optimal Power Flow (SCLOPF). SCLOPF builds on the LOPF by including additional constraints that branches may not become overloaded after the outage of a selection of branches. For each potential outage of a branch _{ℓ}

PyPSA also implements a variety of network clustering algorithms to reduce the number of buses in a network while preserving important transmission lines. For example, the

PyPSA is currently in version 0.11.0. PyPSA has been designed to be modular, so that it is possible to develop the code for many other types of calculations. Currently features being considered by the development team include, in rough order of priority:

Integer transmission expansion, following an existing implementation in PyPSA [

Multi-horizon dynamic investment optimisation over several years, following for example the implementation in OSeMOSYS [

Transient analysis using the Root-Mean-Square (RMS) values of phasor quantities, following the implementation in PSAT [

An implementation of the non-linear power flow solution using analytic continuation in the complex plane [

Short-circuit analysis, following the implementation in pandapower [

OPF with the full non-linear network equations, following the implementations in PYPOWER and MATPOWER;

An interactive web-based GUI for analysing and manipulating the network topology.

PyPSA was written in the Python programming language [

PyPSA stores all data about network components in the DataFrame objects of the Python library pandas [

All matrix calculations and solutions of linear equation systems are carried out either with NumPy [

Optimisation problems are formulated using the Python-based optimization modeling language Pyomo [

PyPSA has no graphical user interface, but integrates closely with the IPython [

Internally PyPSA converts all power system quantities (voltage, power, current, impedances) to per unit values. Set points for loads and generation are stored separately from the power values which are actually dispatched.

PyPSA comes with a large test suite that covers all of its major functionality. Tests are implemented using the Python library pytest [

In this section some examples of PyPSA’s computational performance are given.

In Figure ^{–8} for the summed error in the apparent power

Calculation times for performing a full load flow on the MATPOWER [

For the linear optimal power flow (LOPF) the computation performance depends strongly on the choice of linear solver. To give an indication of typical calculation times, if dispatch in the SciGRID model of the German transmission network described in Section 7 (585 buses, 1423 generators including curtailable wind and solar at each node, 38 pump storage units, 852 lines, 96 transformers) is optimised over 4 snapshots, it takes 5 seconds using the COIN-OR Clp free solver on the computer described above. Extensive timings for different formulations of the LOPF problem can be found in [

Given the proliferation of software tools available for modeling power systems, a guide is provided here that briefly compares PyPSA to other power system tools, with a particular focus on free software in the Python programming language. The advantages of Python are discussed above in Section 3.

Selected features for a selection of different software tools are compared in Table

A comparison of selected features of selected software tools that are similar to PyPSA.

Software | Version | Citation | Free Software | Grid Analysis |
Economic Analysis |
||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|

Power Flow | Continuation Power Flow | Dynamic Analysis | Transport Model | Linear OPF | SCLOPF | Nonlinear OPF | Multi-Period Optimisation | Unit Commitment | Investment Optimisation | Other Energy Sectors | |||||

Power system tools | MATPOWER | 6.0 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ||||||

NEPLAN | 5.5.8 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ||||||

pandapower | 1.4.0 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ||||||||

PowerFactory | 2017 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ||||||||

PowerWorld | 19 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |||||||

PSAT | 2.1.10 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |||||

PSS/E | 33.10 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ||||||||

PSS/SINCAL | 13.5 | [ |
✓ | ✓ | ✓ | ✓ | |||||||||

PYPOWER | 5.1.2 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ||||||||

0.11.0 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ||||||

Energy system tools | calliope | 0.5.2 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | |||||||

minpower | 4.3.10 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ||||||||

MOST | 6.0 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ||||

oemof | 0.1.4 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |||||||

OSeMOSYS | 2017 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ||||||||

PLEXOS | 7.400 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ||||||

PowerGAMA | 1.1 | [ |
✓ | ✓ | ✓ | ✓ | |||||||||

PRIMES | 2017 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |||||||

TIMES | 2017 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |||||||

urbs | 0.7 | [ |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ |

Many power system tools concentrate on steady-state, dynamic (i.e. short-term transient) and single-period OPF analysis of power networks. They neglect the multi-period unit commitment, investment optimisation and energy system coupling which PyPSA offers. In Python we focus our comparison on two tools: PYPOWER and pandapower.

PYPOWER [

PyPSA differs from more general energy system models such as calliope [

These differences with other software tools are the reason that it was decided to develop a new tool rather than to extend an existing one. Existing tools for power flow such as PYPOWER did not have the internal code and data structures for economic optimisation over multiple time periods with many inter-temporal actors, whereas the energy system tools were missing the tight integration with power flow analysis that we believe is necessary for future research.

On the PyPSA website [

The SciGRID model of Germany provides geo-referenced data for substations and transmission lines (220 kV and above). In one code example, data from openly-available sources on power plant locations and capacities, load distribution and time series are added to the SciGRID data so that load flow calculations can be carried out. The results of one such simulation for Germany with nodal pricing is shown in Figure _{n,t}

_{n,t}

The data quality for the transmission grid in OpenStreetMap outside Germany is not of uniform quality, so for the European grid, an extract of the ENTSO-E interactive map [_{2} reduction of 95% compared to 1990 levels, is shown in Figure

Results of optimisation of generation and storage capacities in Europe to reduce CO_{2} emissions in the European electricity sector by 95% compared to 1990 levels [

In this paper a new toolbox has been presented for simulating and optimising power systems. Python for Power System Analysis (PyPSA) provides components to model variable renewable generation, conventional power plants, storage units, coupling to other energy sectors and multiply-connected AC and DC networks over multiple periods for the optimisation of both operation and investment. Tools are also provided for steady-state analysis with the full load flow equations. PyPSA’s performance for large datasets, comparisons with other software packages and several example applications are demonstrated.

As free software, the code of PyPSA can easily be inspected and extended by users, thereby contributing to further research and also transparency in power system modelling. Given that public acceptance of new infrastructure is often low, it is hoped that transparent modelling can contribute to public understanding of the various options we face when designing a sustainable energy system.

GNU/Linux, Mac OSX, Windows and any other operating systems running Python.

Python. PyPSA has been tested with versions 2.7 and 3.5 of Python.

None.

PyPSA is written in pure Python and is available in the Python Package Index (PyPI). PyPSA depends on the following Python libraries that are not in the Python standard library, but all of which are available in PyPI:

NumPy [

SciPy [

pandas [

Pyomo [

networkx (optional for some graph topology algorithms; version 1.10 or later)

pytest (optional for testing)

matplotlib (optional for plotting)

plotly (optional for interactive plotting)

The exact code contributions of each person to version 0.11.0 of PyPSA can be found in the GitHub repository [

Tom Brown, Frankfurt Institute for Advanced Studies

Jonas Hörsch, Frankfurt Institute for Advanced Studies

David Schlachtberger, Frankfurt Institute for Advanced Studies

João Gorenstein Dedecca, Delft University of Technology

Nis Martensen, Energynautics GmbH

Konstantinos Syranidis, Forschungszentrum Jülich

English

Modelling of the electrical power system is becoming increasingly important thanks to the liberalisation of the power system, the rise of variable renewable energy to combat global warming, and the electrification of transport and heating. PyPSA provides a modular, object-oriented framework for simulating power systems that can be used for research and case studies, and also easily extended beyond its existing functionality. To maximise its reuse potential, PyPSA is written as abstractly as possible, making no assumptions about network topology, infrastructure parameters or asset technologies. Judging by traffic on the forum [

Support for new users is provided on the PyPSA website [

Users can contribute towards the code by raising issues or making pull requests on the GitHub repository [

We thank Stefan Schramm for supporting the development of PyPSA. We thank the community of PyPSA users for bug reports, improvement suggestions and their general friendly support and encouragement for the further development of PyPSA.

The authors have no competing interests to declare.