Skip to content

Commit

Permalink
Addition of unsustainable biomass potentials (PyPSA#1139)
Browse files Browse the repository at this point in the history
* add columns to potential df defined by difference to eurostat

* add network components

* add unsustainable bioliquids

* replaced stores by generators, still infeasible

* remove municipal waste

* remove separate treatment of waste from biomass potential calculation

* phase out unsustainble biomass potentials

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* phase-out unsustainable bioliquids

* remove waste_incineration from build_sector rule

* multiple potential calculation for different planning horizons

* raised costs of unsustainable solid biomass

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* stores instead of generators

* change snakemake inputs

* add phas-eout to config

* add techcolor for unsustainable bioliquids

* add config parameter to disable inclusion of unsustainable bioenergy potentials

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* add biomass to params

* remove call of snakemake object in define_spatial

* Quick resolve of review part 1 (config parameters, if-clause-reduction, bioliquid spatial, fix bioliquid link capacity

* Quick resolve of review part 2 (config table, helper function, fixed build_eurostat, removed dir-change, forced unsustainable usage, reverted overnight distinction in Snakefile)

* Cast of planning_horizon parameter to int type after test run

* added JRC fuel costs for solid and liquid biofuels, BtL VOM

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* clean-up after master merge

* adressed review (increase threads for build_eurostat, fixed e_max_pu of Stores, changed version of technology-data); added release note

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: lisazeyen <35347358+lisazeyen@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 7, 2024
1 parent fb41016 commit f8d0efb
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 6 deletions.
20 changes: 19 additions & 1 deletion config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,23 @@ biomass:
- Sludge
municipal solid waste:
- Municipal waste
share_unsustainable_use_retained:
2020: 1
2025: 0.66
2030: 0.33
2035: 0
2040: 0
2045: 0
2050: 0
share_sustainable_potential_available:
2020: 0
2025: 0.33
2030: 0.66
2035: 1
2040: 1
2045: 1
2050: 1


# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#solar-thermal
solar_thermal:
Expand Down Expand Up @@ -737,7 +754,7 @@ industry:
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#costs
costs:
year: 2030
version: v0.9.0
version: v0.9.1
social_discountrate: 0.02
fill_values:
FOM: 0
Expand Down Expand Up @@ -1055,6 +1072,7 @@ plotting:
services rural biomass boiler: '#c6cf98'
services urban decentral biomass boiler: '#dde5b5'
biomass to liquid: '#32CD32'
unsustainable bioliquids: '#32CD32'
electrobiofuels: 'red'
BioSNG: '#123456'
# power transmission
Expand Down
2 changes: 2 additions & 0 deletions doc/configtables/biomass.csv
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ classes ,,,
-- solid biomass,--,Array of biomass comodity,The comodity that are included as solid biomass
-- not included,--,Array of biomass comodity,The comodity that are not included as a biomass potential
-- biogas,--,Array of biomass comodity,The comodity that are included as biogas
share_unsustainable_use_retained,--,Dictionary with planning horizons as keys., Share of unsustainable biomass use retained using primary production of Eurostat data as reference
share_sustainable_potential_available,--,Dictionary with planning horizons as keys., Share determines phase-in of ENSPRESO biomass potentials
4 changes: 4 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Release Notes
Upcoming Release
================

* Added unsustainable biomass potentials for solid, gaseous, and liquid biomass. The potentials can be phased-out and/or
substituted by the phase-in of sustainable biomass types using the config parameters
``biomass: share_unsustainable_use_retained`` and ``biomass: share_sustainable_potential_available``.

* The rule ``prepare_links_p_nom`` was removed since it was outdated and not used.

* Changed heat pump COP approximation for central heating to be based on `Jensen et al. (2018) <https://backend.orbit.dtu.dk/ws/portalfiles/portal/151965635/MAIN_Final.pdf>`__ and a default forward temperature of 90C. This is more realistic for district heating than the previously used approximation method.
Expand Down
6 changes: 4 additions & 2 deletions rules/build_sector.smk
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,8 @@ rule build_biomass_potentials:
"https://zenodo.org/records/10356004/files/ENSPRESO_BIOMASS.xlsx",
keep_local=True,
),
nuts2="data/bundle/nuts/NUTS_RG_10M_2013_4326_LEVL_2.geojson", # https://gisco-services.ec.europa.eu/distribution/v2/nuts/download/#nuts21
eurostat="data/eurostat/Balances-April2023",
nuts2="data/bundle/nuts/NUTS_RG_10M_2013_4326_LEVL_2.geojson",
regions_onshore=resources("regions_onshore_elec_s{simpl}_{clusters}.geojson"),
nuts3_population=ancient("data/bundle/nama_10r_3popgdp.tsv.gz"),
swiss_cantons=ancient("data/ch_cantons.csv"),
Expand All @@ -358,7 +359,7 @@ rule build_biomass_potentials:
biomass_potentials=resources(
"biomass_potentials_s{simpl}_{clusters}_{planning_horizons}.csv"
),
threads: 1
threads: 8
resources:
mem_mb=1000,
log:
Expand Down Expand Up @@ -954,6 +955,7 @@ rule prepare_sector_network:
countries=config_provider("countries"),
adjustments=config_provider("adjustments", "sector"),
emissions_scope=config_provider("energy", "emissions"),
biomass=config_provider("biomass"),
RDIR=RDIR,
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
heat_systems=config_provider("sector", "heat_systems"),
Expand Down
2 changes: 2 additions & 0 deletions rules/retrieve.smk
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ if config["enable"]["retrieve"]:
unpack_archive(params["zip"], output_folder)
os.remove(params["zip"])



if config["enable"]["retrieve"]:

# Download directly from naciscdn.org which is a redirect from naturalearth.com
Expand Down
135 changes: 133 additions & 2 deletions scripts/build_biomass_potentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,51 @@
import numpy as np
import pandas as pd
from _helpers import configure_logging, set_scenario_config
from build_energy_totals import build_eurostat

logger = logging.getLogger(__name__)
AVAILABLE_BIOMASS_YEARS = [2010, 2020, 2030, 2040, 2050]


def _calc_unsustainable_potential(df, df_unsustainable, share_unsus, resource_type):
"""
Calculate the unsustainable biomass potential for a given resource type or
regex.
Parameters
----------
df : pd.DataFrame
The dataframe with sustainable biomass potentials.
df_unsustainable : pd.DataFrame
The dataframe with unsustainable biomass potentials.
share_unsus : float
The share of unsustainable biomass potential retained.
resource_type : str or regex
The resource type to calculate the unsustainable potential for.
Returns
-------
pd.Series
The unsustainable biomass potential for the given resource type or regex.
"""

if "|" in resource_type:
resource_potential = df_unsustainable.filter(regex=resource_type).sum(axis=1)
else:
resource_potential = df_unsustainable[resource_type]

return (
df.apply(
lambda c: c.sum()
/ df.loc[df.index.str[:2] == c.name[:2]].sum().sum()
* resource_potential.loc[c.name[:2]],
axis=1,
)
.mul(share_unsus)
.clip(lower=0)
)


def build_nuts_population_data(year=2013):
pop = pd.read_csv(
snakemake.input.nuts3_population,
Expand Down Expand Up @@ -211,15 +251,104 @@ def convert_nuts2_to_regions(bio_nuts2, regions):
return bio_regions


def add_unsustainable_potentials(df):
"""
Add unsustainable biomass potentials to the given dataframe. The difference
between the data of JRC and Eurostat is assumed to be unsustainable
biomass.
Parameters
----------
df : pd.DataFrame
The dataframe with sustainable biomass potentials.
unsustainable_biomass : str
Path to the file with unsustainable biomass potentials.
Returns
-------
pd.DataFrame
The dataframe with added unsustainable biomass potentials.
"""
if "GB" in snakemake.config["countries"]:
latest_year = 2019
else:
latest_year = 2021
idees_rename = {"GR": "EL", "GB": "UK"}
df_unsustainable = (
build_eurostat(
countries=snakemake.config["countries"],
input_eurostat=snakemake.input.eurostat,
nprocesses=int(snakemake.threads),
)
.xs(
max(min(latest_year, int(snakemake.wildcards.planning_horizons)), 1990),
level=1,
)
.xs("Primary production", level=2)
.droplevel([1, 2, 3])
)

df_unsustainable.index = df_unsustainable.index.str.strip()
df_unsustainable = df_unsustainable.rename(
{v: k for k, v in idees_rename.items()}, axis=0
)

bio_carriers = [
"Primary solid biofuels",
"Biogases",
"Renewable municipal waste",
"Pure biogasoline",
"Blended biogasoline",
"Pure biodiesels",
"Blended biodiesels",
"Pure bio jet kerosene",
"Blended bio jet kerosene",
"Other liquid biofuels",
]

df_unsustainable = df_unsustainable[bio_carriers]

# Phase out unsustainable biomass potentials linearly from 2020 to 2035 while phasing in sustainable potentials
share_unsus = params.get("share_unsustainable_use_retained").get(investment_year)

df_wo_ch = df.drop(df.filter(regex="CH\d", axis=0).index)

# Calculate unsustainable solid biomass
df_wo_ch["unsustainable solid biomass"] = _calc_unsustainable_potential(
df_wo_ch, df_unsustainable, share_unsus, "Primary solid biofuels"
)

# Calculate unsustainable biogas
df_wo_ch["unsustainable biogas"] = _calc_unsustainable_potential(
df_wo_ch, df_unsustainable, share_unsus, "Biogases"
)

# Calculate unsustainable bioliquids
df_wo_ch["unsustainable bioliquids"] = _calc_unsustainable_potential(
df_wo_ch,
df_unsustainable,
share_unsus,
resource_type="gasoline|diesel|kerosene|liquid",
)

share_sus = params.get("share_sustainable_potential_available").get(investment_year)
df *= share_sus

df = df.join(df_wo_ch.filter(like="unsustainable")).fillna(0)

return df


if __name__ == "__main__":
if "snakemake" not in globals():

from _helpers import mock_snakemake

snakemake = mock_snakemake(
"build_biomass_potentials",
simpl="",
clusters="5",
planning_horizons=2050,
clusters="37",
planning_horizons=2020,
)

configure_logging(snakemake)
Expand Down Expand Up @@ -269,6 +398,8 @@ def convert_nuts2_to_regions(bio_nuts2, regions):
grouper = {v: k for k, vv in params["classes"].items() for v in vv}
df = df.T.groupby(grouper).sum().T

df = add_unsustainable_potentials(df)

df *= 1e6 # TWh/a to MWh/a
df.index.name = "MWh/a"

Expand Down
2 changes: 1 addition & 1 deletion scripts/build_shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@
from itertools import takewhile
from operator import attrgetter

import country_converter as coco
import geopandas as gpd
import numpy as np
import pandas as pd
import country_converter as coco
from _helpers import configure_logging, set_scenario_config
from shapely.geometry import MultiPolygon, Polygon

Expand Down
Loading

0 comments on commit f8d0efb

Please sign in to comment.