Skip to content

Commit

Permalink
Refining scenarios (#35)
Browse files Browse the repository at this point in the history
* restrict RES buildout

* decrease FT efficiency

* forbid net export of H2 and Efuels

* allow BEV DSM only after 2025

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

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

* consider SMR CC as fossil hydrogen

* increase offwind-connection FOM

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

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

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

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

* fix imports paths

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

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

* further refine offwind buildout

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

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

* add to previous commit (further refine offwind buildout)

* improve the bev_dsm config option

* generalize mock_snakemake

* hotfix mock_snakemake for this script

* add description to modified costs.csv

* split efuel export bans by  carrier

* [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>
  • Loading branch information
lindnemi and pre-commit-ci[bot] authored Jan 25, 2025
1 parent 4ea3133 commit 5054f59
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 23 deletions.
2 changes: 1 addition & 1 deletion config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ sector:
ICE_upper_degree_factor: 1.6
EV_lower_degree_factor: 0.98
EV_upper_degree_factor: 0.63
bev_dsm: true
bev_dsm: 2030
bev_availability: 0.5
bev_energy: 0.05
bev_charge_efficiency: 0.9
Expand Down
16 changes: 8 additions & 8 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run
run:
prefix: 20250122-demand-scenarios
prefix: 20250124-finalfixes
name:
# - CurrentPolicies
- KN2045_Bal_v4
Expand Down Expand Up @@ -438,25 +438,25 @@ solving:
DE:
2020: 54.5
2025: 69
2030: 157 # EEG2023 Ziel für 2035
2035: 250
2030: 115 # EEG2023 Ziel für 2030
2035: 160 # EEG2023 Ziel für 2040
2040: 250
2045: 250
offwind:
DE:
2020: 7.8
2025: 11.3
2030: 29.3 # uba Projektionsbericht and NEP without delayed BalWin 3
2035: 70
2040: 70
2035: 50 # Planned projects until 2035 (offshore_connection_points.csv) -1.3 GW for potential delays
2040: 65 # Planned projects until 2040 -1.5 GW for potential retirments
2045: 70
solar:
DE:
2020: 53.7
2025: 110 # EEG2023; assumes for 2026: 128 GW, assuming a fair share reached by end of 2025
2030: 309 # EEG2023 Ziel für 2035
2035: 1000
2040: 1000
2030: 235 # PV Ziel 2030 + 20 GW
2035: 400
2040: 800
2045: 1000
Store:
co2 sequestered:
Expand Down
8 changes: 2 additions & 6 deletions config/scenarios.manual.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ CurrentPolicies:
2020: 7.8
2025: 11.3
2030: 17.3 # 12 less than NEP, because of 1 year delay
2035: 35 # 29.3 + a little extra
2040: 70
2045: 70
2035: 40 # 29.3 + half of extra projects
onwind:
DE:
2030: 94.5 # uba Projektionsbericht
Expand Down Expand Up @@ -605,9 +603,7 @@ KN2045minus_WorstCase:
2020: 7.8
2025: 11.3
2030: 17.3 # 12 less than NEP, because of 1 year delay
2035: 35 # 29.3 + a little extra
2040: 70
2045: 70
2035: 40 # 29.3 + half of extra projects
onwind:
DE:
2030: 94.5 # uba Projektionsbericht
Expand Down
2 changes: 1 addition & 1 deletion doc/configtables/sector.csv
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ ICE_lower_degree_factor,--,float,Share increase in energy demand in internal com
ICE_upper_degree_factor,--,float,Share increase in energy demand in internal combustion engine (ICE) for each degree difference between the hot environment and the maximum temperature.
EV_lower_degree_factor,--,float,Share increase in energy demand in electric vehicles (EV) for each degree difference between the cold environment and the minimum temperature.
EV_upper_degree_factor,--,float,Share increase in energy demand in electric vehicles (EV) for each degree difference between the hot environment and the maximum temperature.
bev_dsm,--,"{true, false}",Add the option for battery electric vehicles (BEV) to participate in demand-side management (DSM)
bev_dsm,--,"{true, false} or startyear as int",Add the option for battery electric vehicles (BEV) to participate in demand-side management (DSM). If an int is passed it is interpreted as the year from which on BEV DSM is available.
,,,
bev_availability,--,float,The share for battery electric vehicles (BEV) that are able to do demand side management (DSM)
bev_energy,--,float,The average size of battery electric vehicles (BEV) in MWh
Expand Down
2 changes: 1 addition & 1 deletion scripts/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ def mock_snakemake(
else:
root_dir = Path(root_dir).resolve()

user_in_script_dir = Path.cwd().resolve() == script_dir
user_in_script_dir = Path.cwd().resolve().is_relative_to(Path(script_dir))
if str(submodule_dir) in __file__:
# the submodule_dir path is only need to locate the project dir
os.chdir(Path(__file__[: __file__.find(str(submodule_dir))]))
Expand Down
2 changes: 1 addition & 1 deletion scripts/prepare_sector_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2029,7 +2029,7 @@ def add_EVs(
efficiency=options["bev_charge_efficiency"],
)

if options["bev_dsm"]:
if options["bev_dsm"] and options["bev_dsm"] <= investment_year:
e_nom = (
number_cars
* options["bev_energy"]
Expand Down
60 changes: 60 additions & 0 deletions scripts/pypsa-de/additional_functionality.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,27 @@ def h2_import_limits(n, investment_year, limits_volume_max):
carrier_attribute="",
)

logger.info("Adding H2 export ban")

cname = f"H2_export_ban-{ct}"

n.model.add_constraints(lhs >= 0, name=f"GlobalConstraint-{cname}")

if cname in n.global_constraints.index:
logger.warning(
f"Global constraint {cname} already exists. Dropping and adding it again."
)
n.global_constraints.drop(cname, inplace=True)

n.add(
"GlobalConstraint",
cname,
constant=0,
sense=">=",
type="",
carrier_attribute="",
)


def h2_production_limits(n, investment_year, limits_volume_min, limits_volume_max):
for ct in limits_volume_max["electrolysis"]:
Expand Down Expand Up @@ -647,6 +668,45 @@ def add_h2_derivate_limit(n, investment_year, limits_volume_max):
carrier_attribute="",
)

# The following export bans for DE are added unconditionally, independent of config
ct = "DE"
logger.info("Adding net export bans for H2 derivatives in DE")

for incarrier, outcarrier in [
("EU methanol -> DE methanol", "DE methanol -> EU methanol"),
("EU renewable gas -> DE gas", "DE renewable gas -> EU gas"),
("EU renewable oil -> DE oil", "DE renewable oil -> EU oil"),
]:
incoming = n.links.index[n.links.index == incarrier]
outgoing = n.links.index[n.links.index == outcarrier]
incoming_p = (
n.model["Link-p"].loc[:, incoming] * n.snapshot_weightings.generators
).sum()
outgoing_p = (
n.model["Link-p"].loc[:, outgoing] * n.snapshot_weightings.generators
).sum()

lhs = incoming_p - outgoing_p

cname = f"renewable{incarrier.split()[-1]}_export_ban-{ct}"

n.model.add_constraints(lhs >= 0, name=f"GlobalConstraint-{cname}")

if cname in n.global_constraints.index:
logger.warning(
f"Global constraint {cname} already exists. Dropping and adding it again."
)
n.global_constraints.drop(cname, inplace=True)

n.add(
"GlobalConstraint",
cname,
constant=0,
sense=">=",
type="",
carrier_attribute="",
)


def adapt_nuclear_output(n):
logger.info(
Expand Down
7 changes: 6 additions & 1 deletion scripts/pypsa-de/export_ariadne_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import os
import re
import sys

sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + "/../.."))

from functools import reduce

import numpy as np
Expand Down Expand Up @@ -248,7 +251,9 @@ def _get_h2_fossil_fraction(n):
.sum()
)

h2_fossil_fraction = total_h2_supply.get("SMR") / total_h2_supply.sum()
h2_fossil_fraction = (
total_h2_supply.filter(like="SMR").sum() / total_h2_supply.sum()
)

return h2_fossil_fraction

Expand Down
24 changes: 24 additions & 0 deletions scripts/pypsa-de/modify_cost_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,28 @@ def carbon_component_fossils(costs, co2_price):
f"Setting lifetime of central gas CHP to {costs.at[("central gas CHP" , "lifetime") , "value"]} {costs.at[("central gas CHP" , "lifetime") , "unit"]}."
)

# decrease Fischer-Tropsch efficiency
costs.at[("Fischer-Tropsch", "efficiency"), "value"] = (
1 / costs.at[("Fischer-Tropsch", "hydrogen-input"), "value"]
)
costs.at[("Fischer-Tropsch", "efficiency"), "source"] = "inverse of hydrogen-input"

# increase FOM of offshore wind connection (fix for costs.csv)
costs.loc[("offwind-dc-connection-submarine", "FOM"), "value"] = 0.35
costs.loc[("offwind-dc-connection-submarine", "FOM"), "unit"] = costs.at[
("offwind", "FOM"), "unit"
]
costs.loc[("offwind-dc-connection-underground", "FOM"), "value"] = 0.35
costs.loc[("offwind-dc-connection-underground", "FOM"), "unit"] = costs.at[
("offwind", "FOM"), "unit"
]
costs.loc[("offwind-ac-connection-submarine", "FOM"), "value"] = 0.35
costs.loc[("offwind-ac-connection-submarine", "FOM"), "unit"] = costs.at[
("offwind", "FOM"), "unit"
]
costs.loc[("offwind-ac-connection-underground", "FOM"), "value"] = 0.35
costs.loc[("offwind-ac-connection-underground", "FOM"), "unit"] = costs.at[
("offwind", "FOM"), "unit"
]

costs.to_csv(snakemake.output[0])
6 changes: 2 additions & 4 deletions scripts/pypsa-de/plot_ariadne_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@
import numpy as np
import pandas as pd
import pypsa
from export_ariadne_variables import get_discretized_value, process_postnetworks
from matplotlib.lines import Line2D
from matplotlib.patches import Patch
from matplotlib.ticker import FuncFormatter
from pypsa.plot import add_legend_lines
from pypsa.plot import add_legend_circles, add_legend_lines, add_legend_patches

from scripts._helpers import configure_logging, mock_snakemake, set_scenario_config
from scripts.export_ariadne_variables import get_discretized_value, process_postnetworks
from scripts.plot_power_network import load_projection
from scripts.plot_summary import preferred_order, rename_techs
from scripts.prepare_sector_network import prepare_costs
from scripts.pypsa.plot import add_legend_circles, add_legend_lines, add_legend_patches

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -2449,7 +2448,6 @@ def plot_elec_map_de(
frameon=True,
facecolor="white",
fontsize=14,

)

add_legend_patches(ax, colors, labels, legend_kw=legend_kw_patches)
Expand Down
1 change: 1 addition & 0 deletions scripts/pypsa-de/plot_ariadne_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pandas as pd

from scripts._helpers import mock_snakemake

TWh2PJ = 3.6


Expand Down

0 comments on commit 5054f59

Please sign in to comment.