Pathway Planning
For long-term planning problems where the network is optimised for different time horizons, PyPSA offers functionality optimise the network across multiple investment periods (e.g. 2030, 2040, 2050) simulataneously with perfect foresight.
Literature¶
In the literature, two different methods can be distinguished for pathway optimisation with perfect foresight, mainly differing in the way they handle the investment costs of assets:1
- In Type I, the complete overnight investment costs are applied in the investment period the asset is built.
- In Type II, the investment costs are annualised over the years in which an asset is active (i.e. build year plus lifetime).
PyPSA uses Type II, mainly because it allows a cleaner separation of the discounting over different years and the end-of-horizon effects are smaller compared to Type I. End-of-horizon effects occur when models undervalue long-lived assets and overbuild short-term ones because they ignore system needs beyond the final period.
Implementation¶
Optimisation with multiple investment periods can be run with
n.optimize(multi_investment_periods=True)
Overnight versus pathway optimisation
By default, there are no investment periods defined, and the network is optimised for a single investment period (overnight scenario).
For pathway optimisation, the n.snapshots have to be a pandas.MultiIndex,
with the first level as a subset of the investment periods (see Investment
Periods). The investment periods are defined
in n.investment_periods, a pandas.Index of monotonically increasing integers
of years (e.g. [2030, 2040, 2050]).
Investment periods weightings are stored in n.investment_period_weightings, a
pandas.DataFrame indexed by n.investment_periods with two columns for
objective (\(v_a^o\), for social discounting of costs) and years (\(v_a^y\), for
emission budgets).
The general approach for modelling multiple investment periods is to add
components for each investment period \(a\), in which their capacity should be
extendable (i.e. the investment variables \(G_{s,a}\) are extended by index \(a\)).
For example, optimising wind capacities from 2030 to 2050 in 10-year steps
requires a separate generator for each investment period (e.g. wind-2030,
wind-2040, wind-2050), each with the corresponding build year and lifetime.
This structure enables the specification of differing technological assumptions per investment period, such as decreasing investment costs, improving efficiencies, or better capacity factors from higher hub heights. Moreover, not all technologies need to be available in each investment period. For instance, to forbid new coal power plants after 2025 or to introduce new technologies like small modular nuclear reactors (SMR) only from 2040 onwards.
Objective¶
Info
For illustration purposes, the following outline of the optimisation problem with multiple investment periods is reduced to the case of a single bus, only generators, and only marginal operational costs. The generalisation to multiple nodes, other asset types and cost functions works analogously.
With multiple investment periods, the objective function is expressed by
Where \(a \in A\) represents the investment periods, \(T_a\) the set of snapshots in investment period \(a\), and \(v_a^o\) the objective weighting of the investment period, \(b_s\) is the build year of component \(s\) with lifetime \(L_s\), \(c_{s,a}\) the annualised investment costs (Type II), \(o_{s,a,t}\) the operational costs and \(w_t^o\) the snapshot objective weightings.
Warning
Note that the build_year and lifetime attributes are only used to determined whether a component is active
in a particular investment period. They are not used to annualise the costs to get the capital_cost attribute. This must be done by by the user, because there are use cases where
the capital_cost is calculated from a loan period that is different from the technical lifetime of the component.
Note
Extendable components with build years before the first investment period are considered as non-extendable components, i.e. taking whatever capacity is given for {p,e,s}_nom.
Mapping of symbols to component attributes
| Symbol | Attribute | Type |
|---|---|---|
| \(G_{s,a}\) | n.generators.p_nom_opt |
Decision variable |
| \(g_{s,a,t}\) | n.generators_t.p |
Decision variable |
| \(a\in A\) | n.investment_periods |
Parameter |
| \(c_{s,a}\) | n.generators.capital_cost |
Parameter |
| \(o_{s,a,t}\) | n.generators_t.marginal_cost |
Parameter |
| \(w_t^o\) | n.snapshot_weightings.objective |
Parameter |
| \(v_a^o\) | n.investment_period_weightings.objective |
Parameter |
| \(b_s\) | n.generators.build_year |
Parameter |
| \(L_s\) | n.generators.lifetime |
Parameter |
Constraints¶
Dispatch of Active Components¶
The dispatch variables for inactive components are set to zero. For instance, for a generator \(g_{s,a,t}\) with build year \(b_s\) and lifetime \(L_s\), the dispatch variable is set to zero for all investment periods \(a\) where \(a < b_s\) (not yet built) or \(a \geq b_s + L_s\) (retired):
where \(T_a\) the set of snapshots in investment period \(a\). In the example above, the wind-2030 generator build int 2030 cannot contribute to electricity generation in 2025.
Emission Budgets¶
Global constraints can now be defined as a budget over all investment periods, e.g. for CO2 emissions:
where \(v_a^y\) denotes the elapsed time in years for the investment period \(a\).
They can also be defined as a limit for each investment period, e.g. for CO2 emissions:
Mapping of symbols to component attributes
| Symbol | Attribute | Type |
|---|---|---|
| \(g_{n,s,a,t}\) | n.generators_t.p |
Decision variable |
| \(e_{n,s,a,t}\) | n.stores_t.e |
Decision variable |
| \(soc_{n,s,a,t}\) | n.storage_units_t.state_of_charge |
Decision variable |
| \(\eta_{n,s,a,t}\) | n.generators_t.efficiency |
Parameter |
| \(e_{n,s,a,\textrm{initial}}\) | n.stores.e_initial |
Parameter |
| \(soc_{n,s,a,\textrm{initial}}\) | n.storage_units.state_of_charge_initial |
Parameter |
| \(\rho_s\) | n.carriers.co2_emissions |
Parameter |
| \(w_t^g\) | n.snapshot_weightings.generators |
Parameter |
| \(v_a^y\) | n.investment_period_weightings.years |
Parameter |
| \(\Gamma\) | n.global_constraints.constant |
Parameter |
Expansion Limits¶
The {p,e,s}_nom_{max,min} for each component now refers to the installable limit for
this build year. To ensure that the total capacity of all active components does
not exceed the technical potential in each region, we must add an additional
global constraint placing an expansion limit on the sum of carrier capacities at
each bus \(n\) and investment period \(a\) (type="tech_capacity_expansion_limit").
The limit may even change with each investment period, e.g. due to changes in land use or
city development.
See Expansion Limit and Growth Limit for more details on global constraints for expansion limits.
Storage Cyclicity and Initial Energy Levels¶
The cyclicity constraints for the Store and StorageUnit components and
initial energy levels require special attention in the context of multiple
investment periods.
By default, a storage component with a set initial state of charge (e_initial,
state_of_charge_initial) is not replenished at the beginning of each
investment period, but only once for the first snapshot of the first investment
period. To consider that the storage is filled to the initial state of charge
for each investment period, the state_of_charge_initial_per_period or
e_initial_per_period attribute must be set to True.
By default, the storage cyclicity constraints for a storage with cyclic
behaviour (cyclic_state_of_charge, e_cyclic) are applied across all investment
periods, i.e. the storage is cyclic across all investment periods. To consider that
the storage is cyclic for each investment period, the
cyclic_state_of_charge_per_period or e_cyclic_per_period attribute must be
set to True.
Technological learning
Technological learning, i.e. the reduction of investment costs for technologies over investment periods as experience grows, is currently not yet implemented in PyPSA. However, a study by Zeyen et al. (2023)2 demonstrates how to implement this on top of PyPSA with a MILP formulation of a piecewise-linearised learning curve using SOS2 constraints.
Examples¶
-
Pathway Planning
Optimizes investment decisions across multiple investment periods for a long-term transition pathway with perfect foresight.
-
Myopic Pathway Planning
Optimizes investment decisions across multiple investment periods for a long-term transition pathway with myopic foresight.
-
T. Brown (2020), Multi-Horizon Planning with Perfect Foresight. ↩
-
E. Zeyen, M. Victoria, T. Brown (2023), Endogenous learning for green hydrogen in a sector-coupled energy model for Europe. Nature Communications, 14, 3743, doi:10.1038/s41467-023-39397-2. ↩