pypsa-eur/scripts/build_salt_cavern_potentials.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

91 lines
2.7 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf-8 -*-
2024-02-19 15:21:48 +00:00
# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors
2023-03-06 17:49:23 +00:00
#
# SPDX-License-Identifier: MIT
"""
Build salt cavern potentials for hydrogen storage.
Technical Potential of Salt Caverns for Hydrogen Storage in Europe CC-BY
4.0
https://doi.org/10.20944/preprints201910.0187.v1
https://doi.org/10.1016/j.ijhydene.2019.12.161
Figure 6. Distribution of potential salt cavern sites across Europe with their corresponding
energy densities (cavern storage potential divided by the volume).
Figure 7. Total cavern storage potential in European countries
classified as onshore, offshore and within 50 km of shore.
The regional distribution is taken from the map (Figure 6) and scaled to the
capacities from the bar chart split by nearshore (<50km from sea),
onshore (>50km from sea), offshore (Figure 7).
"""
import geopandas as gpd
import pandas as pd
2024-02-12 10:53:20 +00:00
from _helpers import set_scenario_config
def concat_gdf(gdf_list, crs="EPSG:4326"):
"""
Concatenate multiple geopandas dataframes with common coordinate reference
system (crs).
"""
return gpd.GeoDataFrame(pd.concat(gdf_list), crs=crs)
def load_bus_regions(onshore_path, offshore_path):
"""
Load pypsa-eur on- and offshore regions and concat.
"""
bus_regions_offshore = gpd.read_file(offshore_path)
bus_regions_onshore = gpd.read_file(onshore_path)
bus_regions = concat_gdf([bus_regions_offshore, bus_regions_onshore])
bus_regions = bus_regions.dissolve(by="name", aggfunc="sum")
return bus_regions
def area(gdf):
"""
Returns area of GeoDataFrame geometries in square kilometers.
"""
return gdf.to_crs(epsg=3035).area.div(1e6)
def salt_cavern_potential_by_region(caverns, regions):
# calculate area of caverns shapes
caverns["area_caverns"] = area(caverns)
overlay = gpd.overlay(regions.reset_index(), caverns, keep_geom_type=True)
# calculate share of cavern area inside region
overlay["share"] = area(overlay) / overlay["area_caverns"]
overlay["e_nom"] = overlay.eval(
"capacity_per_area * share * area_caverns / 1000"
) # TWh
2023-10-08 09:20:36 +00:00
return overlay.groupby(["name", "storage_type"]).e_nom.sum().unstack("storage_type")
if __name__ == "__main__":
if "snakemake" not in globals():
2023-03-06 18:09:45 +00:00
from _helpers import mock_snakemake
snakemake = mock_snakemake("build_salt_cavern_potentials", clusters="37")
2024-02-12 10:53:20 +00:00
set_scenario_config(snakemake)
fn_onshore = snakemake.input.regions_onshore
fn_offshore = snakemake.input.regions_offshore
regions = load_bus_regions(fn_onshore, fn_offshore)
caverns = gpd.read_file(snakemake.input.salt_caverns) # GWh/sqkm
caverns_regions = salt_cavern_potential_by_region(caverns, regions)
caverns_regions.to_csv(snakemake.output.h2_cavern_potential)