Skip to content

Commit

Permalink
Merge pull request #283 from Eddy-JV/Small_corrections
Browse files Browse the repository at this point in the history
Adaptation of H2 network options as per paper
  • Loading branch information
hazemakhalek authored Apr 29, 2024
2 parents 96f640c + 2522ff2 commit d668951
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 74 deletions.
3 changes: 3 additions & 0 deletions config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ snapshots:
# atlite:
# cutout: ./cutouts/africa-2013-era5.nc

build_osm_network: # TODO: To Remove this once we merge pypsa-earth and pypsa-earth-sec
force_ac: false # When true, it forces all components (lines and substation) to be AC-only. To be used if DC assets create problem.

solving:
#tmpdir: "path/to/tmp"
options:
Expand Down
34 changes: 25 additions & 9 deletions scripts/prepare_gas_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
snakemake = mock_snakemake(
"prepare_gas_network",
simpl="",
clusters="56",
clusters="10",
)
sets_path_to_root("pypsa-earth-sec")
rootpath = ".."
Expand Down Expand Up @@ -900,16 +900,32 @@ def plot_clustered_gas_network(pipelines, bus_regions_onshore):

pipelines = parse_states(pipelines, bus_regions_onshore)

plot_gas_network(pipelines, country_borders, bus_regions_onshore)
if len(pipelines.loc[pipelines.amount_states_passed >= 2]) > 0:
plot_gas_network(pipelines, country_borders, bus_regions_onshore)

pipelines = cluster_gas_network(pipelines, bus_regions_onshore, length_factor=1.25)
pipelines = cluster_gas_network(
pipelines, bus_regions_onshore, length_factor=1.25
)

pipelines.to_csv(snakemake.output.clustered_gas_network, index=False)

plot_clustered_gas_network(pipelines, bus_regions_onshore)

pipelines.to_csv(snakemake.output.clustered_gas_network, index=False)
average_length = pipelines["length"].mean
print("average_length = ", average_length)

plot_clustered_gas_network(pipelines, bus_regions_onshore)
total_system_capacity = pipelines["GWKm"].sum()
print("total_system_capacity = ", total_system_capacity)

else:
print(
"Countries:"
+ bus_regions_onshore.country.unique().tolist()
+ "has no existing Natral Gas network between the chosen bus regions"
)

average_length = pipelines["length"].mean
print("average_length = ", average_length)
# Create an empty DataFrame with the specified column names
pipelines = {"bus0": [], "bus1": [], "capacity": [], "length": [], "GWKm": []}

total_system_capacity = pipelines["GWKm"].sum()
print("total_system_capacity = ", total_system_capacity)
pipelines = pd.DataFrame(pipelines)
pipelines.to_csv(snakemake.output.clustered_gas_network, index=False)
149 changes: 84 additions & 65 deletions scripts/prepare_sector_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pandas as pd
import pypsa
import pytz
import ruamel.yaml
import xarray as xr
from helpers import (
create_dummy_data,
Expand Down Expand Up @@ -333,13 +334,83 @@ def add_hydrogen(n, costs):
capital_cost=h2_capital_cost,
)

if not snakemake.config["sector"]["hydrogen"]["network_routes"] == "greenfield":
# Hydrogen network:
# -----------------
def add_links_repurposed_H2_pipelines():
n.madd(
"Link",
h2_links.index + " repurposed",
bus0=h2_links.bus0.values + " H2",
bus1=h2_links.bus1.values + " H2",
p_min_pu=-1,
p_nom_extendable=True,
p_nom_max=h2_links.capacity.values
* 0.8, # https://gasforclimate2050.eu/wp-content/uploads/2020/07/2020_European-Hydrogen-Backbone_Report.pdf
length=h2_links.length.values,
capital_cost=costs.at["H2 (g) pipeline repurposed", "fixed"]
* h2_links.length.values,
carrier="H2 pipeline repurposed",
lifetime=costs.at["H2 (g) pipeline repurposed", "lifetime"],
)

def add_links_new_H2_pipelines():
n.madd(
"Link",
h2_links.index,
bus0=h2_links.bus0.values + " H2",
bus1=h2_links.bus1.values + " H2",
p_min_pu=-1,
p_nom_extendable=True,
length=h2_links.length.values,
capital_cost=costs.at["H2 (g) pipeline", "fixed"] * h2_links.length.values,
carrier="H2 pipeline",
lifetime=costs.at["H2 (g) pipeline", "lifetime"],
)

def add_links_elec_routing_new_H2_pipelines():
attrs = ["bus0", "bus1", "length"]
h2_links = pd.DataFrame(columns=attrs)

candidates = pd.concat(
{
"lines": n.lines[attrs],
"links": n.links.loc[n.links.carrier == "DC", attrs],
}
)

for candidate in candidates.index:
buses = [
candidates.at[candidate, "bus0"],
candidates.at[candidate, "bus1"],
]
buses.sort()
name = f"H2 pipeline {buses[0]} -> {buses[1]}"
if name not in h2_links.index:
h2_links.at[name, "bus0"] = buses[0]
h2_links.at[name, "bus1"] = buses[1]
h2_links.at[name, "length"] = candidates.at[candidate, "length"]

n.madd(
"Link",
h2_links.index,
bus0=h2_links.bus0.values + " H2",
bus1=h2_links.bus1.values + " H2",
p_min_pu=-1,
p_nom_extendable=True,
length=h2_links.length.values,
capital_cost=costs.at["H2 (g) pipeline", "fixed"] * h2_links.length.values,
carrier="H2 pipeline",
lifetime=costs.at["H2 (g) pipeline", "lifetime"],
)

# Add H2 Links:
if snakemake.config["sector"]["hydrogen"]["network"]:
h2_links = pd.read_csv(snakemake.input.pipelines)

# Order buses to detect equal pairs for bidirectional pipelines
buses_ordered = h2_links.apply(lambda p: sorted([p.bus0, p.bus1]), axis=1)

if snakemake.config["clustering_options"]["alternative_clustering"]:
if snakemake.config["build_osm_network"]["force_ac"]:
# Appending string for carrier specification '_AC'
h2_links["bus0"] = buses_ordered.str[0] + "_AC"
h2_links["bus1"] = buses_ordered.str[1] + "_AC"
Expand All @@ -365,71 +436,19 @@ def add_hydrogen(n, costs):
h2_links = h2_links.groupby("buses_idx").agg(
{"bus0": "first", "bus1": "first", "length": "mean", "capacity": "sum"}
)
else:
attrs = ["bus0", "bus1", "length"]
h2_links = pd.DataFrame(columns=attrs)

candidates = pd.concat(
{
"lines": n.lines[attrs],
"links": n.links.loc[n.links.carrier == "DC", attrs],
}
)

for candidate in candidates.index:
buses = [candidates.at[candidate, "bus0"], candidates.at[candidate, "bus1"]]
buses.sort()
name = f"H2 pipeline {buses[0]} -> {buses[1]}"
if name not in h2_links.index:
h2_links.at[name, "bus0"] = buses[0]
h2_links.at[name, "bus1"] = buses[1]
h2_links.at[name, "length"] = candidates.at[candidate, "length"]

# TODO Add efficiency losses
if snakemake.config["sector"]["hydrogen"]["network"]:
if snakemake.config["sector"]["hydrogen"]["gas_network_repurposing"]:
n.madd(
"Link",
h2_links.index + " repurposed",
bus0=h2_links.bus0.values + " H2",
bus1=h2_links.bus1.values + " H2",
p_min_pu=-1,
p_nom_extendable=True,
p_nom_max=h2_links.capacity.values
* 0.8, # https://gasforclimate2050.eu/wp-content/uploads/2020/07/2020_European-Hydrogen-Backbone_Report.pdf
length=h2_links.length.values,
capital_cost=costs.at["H2 (g) pipeline repurposed", "fixed"]
* h2_links.length.values,
carrier="H2 pipeline repurposed",
lifetime=costs.at["H2 (g) pipeline repurposed", "lifetime"],
)
n.madd(
"Link",
h2_links.index,
bus0=h2_links.bus0.values + " H2",
bus1=h2_links.bus1.values + " H2",
p_min_pu=-1,
p_nom_extendable=True,
length=h2_links.length.values,
capital_cost=costs.at["H2 (g) pipeline", "fixed"]
* h2_links.length.values,
carrier="H2 pipeline",
lifetime=costs.at["H2 (g) pipeline", "lifetime"],
)
if len(h2_links) > 0:
if snakemake.config["sector"]["hydrogen"]["gas_network_repurposing"]:
add_links_elec_routing_new_H2_pipelines()
if snakemake.config["sector"]["hydrogen"]["network_routes"] == "greenfield":
add_links_elec_routing_new_H2_pipelines()
else:
add_links_new_H2_pipelines()
else:
n.madd(
"Link",
h2_links.index,
bus0=h2_links.bus0.values + " H2",
bus1=h2_links.bus1.values + " H2",
p_min_pu=-1,
p_nom_extendable=True,
length=h2_links.length.values,
capital_cost=costs.at["H2 (g) pipeline", "fixed"]
* h2_links.length.values,
carrier="H2 pipeline",
lifetime=costs.at["H2 (g) pipeline", "lifetime"],
)
print(
"No existing gas network; applying greenfield for H2 network"
) # TODO change to logger.info
add_links_elec_routing_new_H2_pipelines()


def define_spatial(nodes):
Expand Down
3 changes: 3 additions & 0 deletions test/config.test1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ snapshots:
# atlite:
# cutout: ./cutouts/africa-2013-era5.nc

build_osm_network: # TODO: To Remove this once we merge pypsa-earth and pypsa-earth-sec
force_ac: false # When true, it forces all components (lines and substation) to be AC-only. To be used if DC assets create problem.

solving:
#tmpdir: "path/to/tmp"
options:
Expand Down

0 comments on commit d668951

Please sign in to comment.