add existing wind and solar capacities based on IRENASTATS

This commit is contained in:
Fabian Neumann 2022-04-04 19:03:09 +02:00
parent 215d18cb31
commit ade22bf4f0
4 changed files with 60 additions and 27 deletions

View File

@ -58,10 +58,20 @@ electricity:
conventional_carriers: [nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass] conventional_carriers: [nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass]
renewable_capacities_from_OPSD: [] # onwind, offwind, solar renewable_capacities_from_OPSD: [] # onwind, offwind, solar
# estimate_renewable_capacities_from_capacity_stats: estimate_renewable_capacities:
# # Wind is the Fueltype in ppm.data.Capacity_stats, onwind, offwind-{ac,dc} the carrier in PyPSA-Eur # Renewable capacities are based on existing capacities reported by IRENA
# Wind: [onwind, offwind-ac, offwind-dc]
# Solar: [solar] # Reference year, any of 2000 to 2020
year: 2020
# Artificially limit maximum capacities to factor * (IRENA capacities),
# i.e. 110% of <years>'s capacities => expansion_limit: 1.1
# false: Use estimated renewable potentials determine by the workflow
expansion_limit: false
technology_mapping:
# Wind is the Fueltype in ppm.data.Capacity_stats, onwind, offwind-{ac,dc} the carrier in PyPSA-Eur
Offshore: [offwind-ac, offwind-dc]
Onshore: [onwind]
PV: [solar]
atlite: atlite:
nprocesses: 4 nprocesses: 4

View File

@ -7,6 +7,26 @@
Release Notes Release Notes
########################################## ##########################################
Energy Security Release (April 2022)
====================================
**New Features and Changes**
* Added existing renewable capacities for all countries based on IRENA statistics (IRENASTAT) using new ``powerplantmatching`` version:
* Configuration of reference year for capacities can be configured (default: ``2020``)
* Uniform expansion limit of renewable build-up based on existing capacities can be configured using ``expansion_limit`` option
(default: ``false``; limited to determined renewable potentials)
* Distribution of country-level capacities proportional to maximum annual energy yield for each bus region
* This functionality was previously using OPSD data.
* The corresponding ``config`` entries changed, cf. ``config.default.yaml``:
* old: ``estimate_renewable_capacities_from_capacity_stats``
* new: ``estimate_renewable_capacities``
**Bugs and Compatibility**
* ``powerplantmatching>=0.5.1`` is now required for ``IRENASTATS``.
Synchronisation Release - Ukraine and Moldova (17th March 2022) Synchronisation Release - Ukraine and Moldova (17th March 2022)
=============================================================== ===============================================================

View File

@ -24,7 +24,7 @@ dependencies:
- yaml - yaml
- pytables - pytables
- lxml - lxml
- powerplantmatching>=0.4.8 - powerplantmatching>=0.5.1
- numpy - numpy
- pandas - pandas
- geopandas - geopandas

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: : 2017-2020 The PyPSA-Eur Authors # SPDX-FileCopyrightText: : 2017-2022 The PyPSA-Eur Authors
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
@ -491,29 +491,29 @@ def attach_OPSD_renewables(n, techs):
def estimate_renewable_capacities(n, tech_map): def estimate_renewable_capacities(n, config):
if len(tech_map) == 0: return if not config["electricity"]["estimate_renewable_capacities"]: return
capacities = (pm.data.Capacity_stats().powerplant.convert_country_to_alpha2() year = config["electricity"]["estimate_renewable_capacities"]["year"]
[lambda df: df.Energy_Source_Level_2] tech_map = config["electricity"]["estimate_renewable_capacities"]["technology_mapping"]
.set_index(['Fueltype', 'Country']).sort_index()) tech_keys = list(tech_map.keys())
countries = config["countries"]
countries = n.buses.country.unique() expansion_limit = config["electricity"]["estimate_renewable_capacities"]["expansion_limit"]
if len(countries) == 0: return if len(countries) == 0: return
if len(tech_map) == 0: return
logger.info('heuristics applied to distribute renewable capacities [MW] \n{}' capacities = pm.data.IRENASTAT().powerplant.convert_country_to_alpha2()
.format(capacities.query('Fueltype in @tech_map.keys() and Capacity >= 0.1') capacities = capacities.query("Year == @year and Technology in @tech_keys and Country in @countries")
.groupby('Country').agg({'Capacity': 'sum'}))) capacities = capacities.groupby(["Technology", "Country"]).Capacity.sum()
for ppm_fueltype, techs in tech_map.items(): logger.info(f"Heuristics applied to distribute renewable capacities [MW] "
tech_capacities = capacities.loc[ppm_fueltype, 'Capacity']\ f"{capacities.groupby('Country').sum()}")
.reindex(countries, fill_value=0.)
#tech_i = n.generators.query('carrier in @techs').index for ppm_technology, techs in tech_map.items():
tech_i = (n.generators.query('carrier in @techs') tech_capacities = capacities.loc[ppm_technology].reindex(countries, fill_value=0.)
[n.generators.query('carrier in @techs') tech_i = n.generators.query('carrier in @techs').index
.bus.map(n.buses.country).isin(countries)].index)
n.generators.loc[tech_i, 'p_nom'] = ( n.generators.loc[tech_i, 'p_nom'] = (
(n.generators_t.p_max_pu[tech_i].mean() * (n.generators_t.p_max_pu[tech_i].mean() *
n.generators.loc[tech_i, 'p_nom_max']) # maximal yearly generation n.generators.loc[tech_i, 'p_nom_max']) # maximal yearly generation
@ -522,6 +522,11 @@ def estimate_renewable_capacities(n, tech_map):
.where(lambda s: s>0.1, 0.)) # only capacities above 100kW .where(lambda s: s>0.1, 0.)) # only capacities above 100kW
n.generators.loc[tech_i, 'p_nom_min'] = n.generators.loc[tech_i, 'p_nom'] n.generators.loc[tech_i, 'p_nom_min'] = n.generators.loc[tech_i, 'p_nom']
if expansion_limit:
assert np.isscalar(expansion_limit)
logger.info(f"Reducing capacity expansion limit to {expansion_limit*100:.2f}% of installed capacity.")
n.generators.loc[tech_i, 'p_nom_max'] = float(expansion_limit) * n.generators.loc[tech_i, 'p_nom_min']
def add_nice_carrier_names(n, config): def add_nice_carrier_names(n, config):
carrier_i = n.carriers.index carrier_i = n.carriers.index
@ -565,11 +570,9 @@ if __name__ == "__main__":
carriers = snakemake.config['electricity']['extendable_carriers']['Generator'] carriers = snakemake.config['electricity']['extendable_carriers']['Generator']
attach_extendable_generators(n, costs, ppl, carriers) attach_extendable_generators(n, costs, ppl, carriers)
tech_map = snakemake.config['electricity'].get('estimate_renewable_capacities_from_capacity_stats', {}) estimate_renewable_capacities(n, snakemake.config)
estimate_renewable_capacities(n, tech_map)
techs = snakemake.config['electricity'].get('renewable_capacities_from_OPSD', []) techs = snakemake.config['electricity'].get('renewable_capacities_from_OPSD', [])
attach_OPSD_renewables(n, techs) attach_OPSD_renewables(n, techs)
update_p_nom_max(n) update_p_nom_max(n)
add_nice_carrier_names(n, snakemake.config) add_nice_carrier_names(n, snakemake.config)