013b705ee4
* Cluster first: build renewable profiles and add all assets after clustering * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * correction: pass landfall_lengths through functions * assign landfall_lenghts correctly * remove parameter add_land_use_constraint * fix network_dict * calculate distance to shoreline, remove underwater_fraction * adjust simplification parameter to exclude Crete from offshore wind connections * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * remove unused geth2015 hydro capacities * removing remaining traces of {simpl} wildcard * add release notes and update workflow graphics * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: lisazeyen <lisa.zeyen@web.de>
91 lines
2.7 KiB
Python
91 lines
2.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors
|
|
#
|
|
# 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
|
|
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
|
|
|
|
return overlay.groupby(["name", "storage_type"]).e_nom.sum().unstack("storage_type")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if "snakemake" not in globals():
|
|
from _helpers import mock_snakemake
|
|
|
|
snakemake = mock_snakemake("build_salt_cavern_potentials", clusters="37")
|
|
|
|
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)
|