From 01f201743d195b177eda9d0f7274fbde80bc8add Mon Sep 17 00:00:00 2001 From: euronion <42553970+euronion@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:30:21 +0100 Subject: [PATCH] Implement everywhere_powerplants --- config/config.default.yaml | 1 + doc/configtables/electricity.csv | 2 ++ doc/release_notes.rst | 6 ++--- rules/build_electricity.smk | 1 + scripts/build_powerplants.py | 40 +++++++++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/config/config.default.yaml b/config/config.default.yaml index b37aaac0..7ef08e2f 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -116,6 +116,7 @@ electricity: powerplants_filter: (DateOut >= 2022 or DateOut != DateOut) custom_powerplants: false + everywhere_powerplants: [nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass] conventional_carriers: [nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass] renewable_carriers: [solar, onwind, offwind-ac, offwind-dc, hydro] diff --git a/doc/configtables/electricity.csv b/doc/configtables/electricity.csv index 00eec0c4..22a22d57 100644 --- a/doc/configtables/electricity.csv +++ b/doc/configtables/electricity.csv @@ -24,6 +24,8 @@ powerplants_filter,--,"use `pandas.query `_ strings here, e.g. ``Country in ['Germany']``",Filter query for the custom powerplant database. ,,, +everywhere_powerplants,--,"Any subset of {nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass}","List of conventional power plants to add to every node in the model with zero initial capacity. To be used in combination with ``extendable_carriers`` to allow for building conventional powerplants irrespective of existing locations." +,,, conventional_carriers,--,"Any subset of {nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass}","List of conventional power plants to include in the model from ``resources/powerplants.csv``. If an included carrier is also listed in ``extendable_carriers``, the capacity is taken as a lower bound." ,,, renewable_carriers,--,"Any subset of {solar, onwind, offwind-ac, offwind-dc, hydro}",List of renewable generators to include in the model. diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 2675e4c6..d9583065 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -7,10 +7,10 @@ Release Notes ########################################## -.. Upcoming Release -.. ================ +Upcoming Release +================ -.. * new features +* New configuration option ``everywhere_powerplants`` to build conventional powerplants everywhere, irrespective of existing powerplants locations, in the network (https://github.com/PyPSA/pypsa-eur/pull/848). PyPSA-Eur 0.9.0 (5th January 2024) ================================== diff --git a/rules/build_electricity.smk b/rules/build_electricity.smk index 8cba33bc..6b092638 100644 --- a/rules/build_electricity.smk +++ b/rules/build_electricity.smk @@ -41,6 +41,7 @@ rule build_powerplants: params: powerplants_filter=config["electricity"]["powerplants_filter"], custom_powerplants=config["electricity"]["custom_powerplants"], + everywhere_powerplants=config["electricity"]["everywhere_powerplants"], countries=config["countries"], input: base_network=RESOURCES + "networks/base.nc", diff --git a/scripts/build_powerplants.py b/scripts/build_powerplants.py index d6553663..69920aa7 100755 --- a/scripts/build_powerplants.py +++ b/scripts/build_powerplants.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# SPDX-FileCopyrightText: : 2017-2023 The PyPSA-Eur Authors +# SPDX-FileCopyrightText: : 2017-2024 The PyPSA-Eur Authors # # SPDX-License-Identifier: MIT @@ -10,6 +10,7 @@ Retrieves conventional powerplant capacities and locations from these to buses and creates a ``.csv`` file. It is possible to amend the powerplant database with custom entries provided in ``data/custom_powerplants.csv``. +Lastly, for every substation, powerplants with zero-initial capacity can be added for certain fuel types automatically. Relevant Settings ----------------- @@ -19,6 +20,7 @@ Relevant Settings electricity: powerplants_filter: custom_powerplants: + everywhere_powerplants: .. seealso:: Documentation of the configuration file ``config/config.yaml`` at @@ -44,6 +46,7 @@ Description ----------- The configuration options ``electricity: powerplants_filter`` and ``electricity: custom_powerplants`` can be used to control whether data should be retrieved from the original powerplants database or from custom amendmends. These specify `pandas.query `_ commands. +In addition the configuration option ``electricity: everywhere_powerplants`` can be used to place powerplants with zero-initial capacity of certain fuel types at all substations. 1. Adding all powerplants from custom: @@ -73,10 +76,18 @@ The configuration options ``electricity: powerplants_filter`` and ``electricity: powerplants_filter: Country not in ['Germany'] and YearCommissioned <= 2015 custom_powerplants: YearCommissioned <= 2015 + +4. Adding powerplants at all substations for 4 conventional carrier types: + + .. code:: yaml + + everywhere_powerplants: ['Natural Gas', 'Coal', 'nuclear', 'OCGT'] """ import logging +import itertools +import numpy as np import pandas as pd import powerplantmatching as pm import pypsa @@ -96,6 +107,28 @@ def add_custom_powerplants(ppl, custom_powerplants, custom_ppl_query=False): [ppl, add_ppls], sort=False, ignore_index=True, verify_integrity=True ) +def add_everywhere_powerplants(ppl, substations, everywhere_powerplants): + # Create a dataframe with "everywhere_powerplants" of stated carriers at the location of all substations + generic_ppl = ( + pd.DataFrame(itertools.product(substations.index.values, everywhere_powerplants), columns=["substation_index","Fueltype"]) + .merge(substations[["x","y","country"]], left_on="substation_index", right_index=True) + ).drop(columns="substation_index") + + # PPL uses different columns names compared to substations dataframe -> rename + everywhere_ppl = everywhere_ppl.rename(columns={"x":"lon","y":"lat","country":"Country"}) + + # Add default values for the generic powerplants + everywhere_ppl["Name"] = "Automatically added everywhere-powerplant " + generic_ppl.Fueltype + everywhere_ppl["Set"] = "PP" + everywhere_ppl["Technology"] = generic_ppl["Fueltype"] + everywhere_ppl["Capacity"] = 0.0 + + # NaN values for efficiency will be replaced by the generic efficiency by attach_conventional_generators(...) in add_electricity.py later + everywhere_ppl["Efficiency"] = np.nan + + return pd.concat( + [ppl, everywhere_ppl], sort=False, ignore_index=True, verify_integrity=True + ) def replace_natural_gas_technology(df): mapping = {"Steam Turbine": "CCGT", "Combustion Engine": "OCGT"} @@ -149,6 +182,11 @@ if __name__ == "__main__": if countries_wo_ppl := set(countries) - set(ppl.Country.unique()): logging.warning(f"No powerplants known in: {', '.join(countries_wo_ppl)}") + # Add "everywhere powerplants" to all bus locations + ppl = add_everywhere_powerplants( + ppl, n.buses.query("substation_lv"), snakemake.params.everywhere_powerplants + ) + substations = n.buses.query("substation_lv") ppl = ppl.dropna(subset=["lat", "lon"]) ppl = map_country_bus(ppl, substations)