Skip to content
This repository was archived by the owner on Mar 27, 2025. It is now read-only.

Commit dc8baf1

Browse files
Bugfix discretized line capacity (#280)
* improve processing of postnetworks, fix missing trassenlänge * remove duplicate line * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * improve robustness of trassenlänge division * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * divide instead of multiply * [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>
1 parent eb816c5 commit dc8baf1

File tree

5 files changed

+61
-73
lines changed

5 files changed

+61
-73
lines changed

config/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ solving:
409409
max_iterations: 1 # settings for post-discretization: 1
410410
post_discretization:
411411
enable: false
412-
line_unit_size: 1700
412+
line_unit_size: 1698
413413
line_threshold: 0.3
414414
link_unit_size:
415415
DC: 1000

workflow/scripts/additional_functionality.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def h2_production_limits(n, investment_year, limits_volume_min, limits_volume_ma
234234
efficiency = n.links.loc[production, "efficiency"]
235235

236236
lhs = (
237-
n.model["Link-p"].loc[:, production]
237+
n.model["Link-p"].loc[:, production]
238238
* n.snapshot_weightings.generators
239239
* efficiency
240240
).sum()
@@ -662,6 +662,7 @@ def adapt_nuclear_output(n):
662662
carrier_attribute="",
663663
)
664664

665+
665666
def additional_functionality(n, snapshots, snakemake):
666667

667668
logger.info("Adding Ariadne-specific functionality")

workflow/scripts/build_wasserstoff_kernnetz.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,6 @@ def assign_locations(df, locations):
365365

366366
# calc length of points
367367
length_factor = 1.0
368-
length_factor = 1.0
369368
df["length_haversine"] = df.apply(
370369
lambda p: length_factor
371370
* haversine_pts([p.point0.x, p.point0.y], [p.point1.x, p.point1.y]),

workflow/scripts/export_ariadne_variables.py

Lines changed: 56 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4425,11 +4425,13 @@ def get_grid_capacity(n, region, year):
44254425
] *= 0.5
44264426

44274427
# NEP subsets
4428+
current_year = n.generators.build_year.max()
44284429
nep_dc = dc_links.query(
4429-
"index.str.startswith('DC') or index=='TYNDP2020_1' or index=='TYNDP2020_2' or index=='TYNDP2020_23'"
4430+
"(index.str.startswith('DC') or index.str.startswith('TYNDP')) and build_year > 2025 and (@current_year - 5 < build_year <= @current_year)"
4431+
).index
4432+
nep_ac = ac_lines.query(
4433+
"(build_year > 2025) and (@current_year - 5 < build_year <= @current_year)"
44304434
).index
4431-
nep_ac = ac_lines.query("build_year > 2000").index
4432-
44334435
var["Capacity|Electricity|Transmission|DC"] = (
44344436
dc_links.eval("p_nom_opt * length").sum() * MW2GW
44354437
)
@@ -4448,15 +4450,15 @@ def get_grid_capacity(n, region, year):
44484450
snakemake.params.post_discretization["link_unit_size"]["DC"]
44494451
- 5 # To account for numerical errors subtract a small capacity
44504452
)
4451-
.multiply(snakemake.params.post_discretization["link_unit_size"]["DC"] / 2000)
4453+
.div(2000 // (snakemake.params.post_discretization["link_unit_size"]["DC"] - 5))
44524454
.multiply(dc_links.length)
44534455
.sum()
44544456
)
44554457
var["Length Additions|Electricity|Transmission|DC|NEP"] = (
44564458
dc_links.loc[nep_dc]
44574459
.eval("p_nom_opt - p_nom_min")
44584460
.floordiv(snakemake.params.post_discretization["link_unit_size"]["DC"] - 5)
4459-
.multiply(snakemake.params.post_discretization["link_unit_size"]["DC"] / 2000)
4461+
.div(2000 // (snakemake.params.post_discretization["link_unit_size"]["DC"] - 5))
44604462
.multiply(dc_links.length)
44614463
.sum()
44624464
)
@@ -4474,18 +4476,18 @@ def get_grid_capacity(n, region, year):
44744476
)
44754477
var["Length Additions|Electricity|Transmission|AC"] = (
44764478
ac_lines.eval("s_nom_opt - s_nom_min")
4477-
.floordiv(snakemake.params.post_discretization["line_unit_size"] - 5)
4478-
.mul(
4479-
snakemake.params.post_discretization["line_unit_size"] / (2 * 2633)
4480-
) # Trassen size is 2 * 2633, we allow "fractional Trassen" to account for different line types
4479+
.floordiv(
4480+
snakemake.params.post_discretization["line_unit_size"] - 5
4481+
) # To account for numerical errors subtract a small capacity
4482+
.div(5265 // (snakemake.params.post_discretization["line_unit_size"] - 5))
44814483
.multiply(ac_lines.length)
44824484
.sum()
44834485
)
44844486
var["Length Additions|Electricity|Transmission|AC|NEP"] = (
44854487
ac_lines.loc[nep_ac]
44864488
.eval("s_nom_opt - s_nom_min")
44874489
.floordiv(snakemake.params.post_discretization["line_unit_size"] - 5)
4488-
.mul(snakemake.params.post_discretization["line_unit_size"] / (2 * 2633))
4490+
.div(5265 // (snakemake.params.post_discretization["line_unit_size"] - 5))
44894491
.multiply(ac_lines.length)
44904492
.sum()
44914493
)
@@ -4530,7 +4532,7 @@ def get_grid_capacity(n, region, year):
45304532
return var
45314533

45324534

4533-
def hack_DC_projects(n, n_start, model_year, snakemake, costs):
4535+
def hack_DC_projects(n, p_nom_start, p_nom_planned, model_year, snakemake, costs):
45344536

45354537
logger.info(f"Hacking DC projects for year {model_year}")
45364538

@@ -4548,30 +4550,10 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
45484550
]
45494551
past_projects = tprojs[n.links.loc[tprojs, "build_year"] <= (model_year - 5)]
45504552

4551-
logger.info("Post-Discretizing DC projects")
4552-
4553-
p_nom_start = n_start.links.loc[current_projects, "p_nom"].apply(
4554-
lambda x: get_discretized_value(
4555-
x,
4556-
snakemake.params.post_discretization["link_unit_size"]["DC"],
4557-
snakemake.params.post_discretization["link_threshold"]["DC"],
4558-
)
4559-
)
4560-
4561-
# The values in p_nom_opt may already be discretized, here we make sure that
4562-
# the same logic is applied to p_nom and p_nom_min
4563-
for attr in ["p_nom_opt", "p_nom", "p_nom_min"]:
4564-
n.links.loc[tprojs, attr] = n.links.loc[tprojs, attr].apply(
4565-
lambda x: get_discretized_value(
4566-
x,
4567-
snakemake.params.post_discretization["link_unit_size"]["DC"],
4568-
snakemake.params.post_discretization["link_threshold"]["DC"],
4569-
)
4570-
)
45714553
for proj in tprojs:
4572-
if not isclose(n.links.loc[proj, "p_nom"], n_start.links.loc[proj, "p_nom"]):
4554+
if not isclose(n.links.loc[proj, "p_nom"], p_nom_planned[proj]):
45734555
logger.warning(
4574-
f"Changed p_nom of {proj} from {n_start.links.loc[proj, 'p_nom']} to {n.links.loc[proj, 'p_nom']}"
4556+
f"(Post-)discretization changed p_nom of {proj} from {p_nom_planned[proj]} to {n.links.loc[proj, 'p_nom']}"
45754557
)
45764558

45774559
# Future projects should not have any capacity
@@ -4587,7 +4569,7 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
45874569
if (snakemake.params.NEP_year == 2021) or (
45884570
snakemake.params.NEP_transmission == "overhead"
45894571
):
4590-
logger.warning("Switching DC projects to NEP23 costs post-optimization")
4572+
logger.warning("Switching DC projects to NEP23 and underground costs.")
45914573
n.links.loc[current_projects, "overnight_cost"] = (
45924574
n.links.loc[current_projects, "length"]
45934575
* (
@@ -4601,22 +4583,23 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
46014583
+ costs[0].at["HVDC inverter pair", "investment"] / 1e-9
46024584
)
46034585
# Current projects should have their p_nom_opt bigger or equal to p_nom until the year 2030 (Startnetz that we force in)
4586+
# TODO 2030 is hard coded but should be read from snakemake config
46044587
if model_year <= 2030:
46054588
assert (
46064589
n.links.loc[current_projects, "p_nom_opt"] + 0.1
46074590
>= n.links.loc[current_projects, "p_nom"]
46084591
).all()
46094592

4610-
n.links.loc[current_projects, "p_nom"] -= p_nom_start
4611-
n.links.loc[current_projects, "p_nom_min"] -= p_nom_start
4593+
n.links.loc[current_projects, "p_nom"] -= p_nom_start[current_projects]
4594+
n.links.loc[current_projects, "p_nom_min"] -= p_nom_start[current_projects]
46124595

46134596
else:
46144597
n.links.loc[current_projects, "p_nom"] = n.links.loc[
46154598
current_projects, "p_nom_min"
46164599
]
46174600

46184601
# Past projects should have their p_nom_opt bigger or equal to p_nom
4619-
if model_year <= 2035:
4602+
if model_year <= 2030 + 5:
46204603
assert (
46214604
n.links.loc[past_projects, "p_nom_opt"] + 0.1 # numerical error tolerance
46224605
>= n.links.loc[past_projects, "p_nom"]
@@ -4625,53 +4608,58 @@ def hack_DC_projects(n, n_start, model_year, snakemake, costs):
46254608
return n
46264609

46274610

4628-
def hack_AC_projects(n, n_start, model_year, snakemake):
4611+
def hack_AC_projects(n, s_nom_start, model_year, snakemake):
46294612
logger.info(f"Hacking AC projects for year {model_year}")
46304613

4631-
# All transmission projects have build_year > 0, this is implicit in the query
4632-
ac_projs = n.lines.query("build_year > 0").index
46334614
current_projects = n.lines.query(
46344615
"@model_year - 5 < build_year <= @model_year"
46354616
).index
46364617

4637-
logger.info("Post-Discretizing AC projects")
4638-
4639-
for attr in ["s_nom_opt", "s_nom", "s_nom_min"]:
4640-
# The values in s_nom_opt may already be discretized, here we make sure that
4641-
# the same logic is applied to s_nom and s_nom_min
4642-
n.lines.loc[ac_projs, attr] = n.lines.loc[ac_projs, attr].apply(
4643-
lambda x: get_discretized_value(
4644-
x,
4645-
snakemake.params.post_discretization["line_unit_size"],
4646-
snakemake.params.post_discretization["line_threshold"],
4647-
)
4648-
)
4649-
4650-
s_nom_start = n_start.lines.loc[current_projects, "s_nom"].apply(
4651-
lambda x: get_discretized_value(
4652-
x,
4653-
snakemake.params.post_discretization["line_unit_size"],
4654-
snakemake.params.post_discretization["line_threshold"],
4655-
)
4656-
)
4657-
46584618
if snakemake.params.NEP_year == 2021:
46594619
logger.warning("Switching AC projects to NEP23 costs post-optimization")
46604620
n.lines.loc[current_projects, "overnight_cost"] *= 772 / 472
46614621

46624622
# Eventhough the lines are available to the model from the start,
4663-
# we pretend that the lines were in expanded in this year
4623+
# we pretend that the lines were expanded in the current year
46644624
# s_nom_start is used, because the model may expand lines
46654625
# endogenously before that or after that
4666-
n.lines.loc[current_projects, "s_nom"] -= s_nom_start
4667-
n.lines.loc[current_projects, "s_nom_min"] -= s_nom_start
4626+
n.lines.loc[current_projects, "s_nom"] -= s_nom_start[current_projects]
4627+
n.lines.loc[current_projects, "s_nom_min"] -= s_nom_start[current_projects]
46684628

46694629
return n
46704630

46714631

4672-
def hack_transmission_projects(n, n_start, model_year, snakemake, costs):
4673-
n = hack_DC_projects(n, n_start, model_year, snakemake, costs)
4674-
n = hack_AC_projects(n, n_start, model_year, snakemake)
4632+
def process_postnetworks(n, n_start, model_year, snakemake, costs):
4633+
4634+
logger.info("Post-Discretizing DC links")
4635+
_dc_lambda = lambda x: get_discretized_value(
4636+
x,
4637+
snakemake.params.post_discretization["link_unit_size"]["DC"],
4638+
snakemake.params.post_discretization["link_threshold"]["DC"],
4639+
)
4640+
for attr in ["p_nom_opt", "p_nom", "p_nom_min"]:
4641+
# The values in p_nom_opt may already be discretized, here we make sure that
4642+
# the same logic is applied to p_nom and p_nom_min
4643+
n.links[attr] = n.links[attr].apply(_dc_lambda)
4644+
4645+
p_nom_planned = n_start.links["p_nom"]
4646+
p_nom_start = n_start.links["p_nom"].apply(_dc_lambda)
4647+
4648+
logger.info("Post-Discretizing AC lines")
4649+
_ac_lambda = lambda x: get_discretized_value(
4650+
x,
4651+
snakemake.params.post_discretization["line_unit_size"],
4652+
snakemake.params.post_discretization["line_threshold"],
4653+
)
4654+
for attr in ["s_nom_opt", "s_nom", "s_nom_min"]:
4655+
# The values in s_nom_opt may already be discretized, here we make sure that
4656+
# the same logic is applied to s_nom and s_nom_min
4657+
n.lines[attr] = n.lines[attr].apply(_ac_lambda)
4658+
4659+
s_nom_start = n_start.lines["s_nom"].apply(_ac_lambda)
4660+
4661+
n = hack_DC_projects(n, p_nom_start, p_nom_planned, model_year, snakemake, costs)
4662+
n = hack_AC_projects(n, s_nom_start, model_year, snakemake)
46754663
return n
46764664

46774665

@@ -4878,7 +4866,7 @@ def get_data(
48784866
modelyears = [fn[-7:-3] for fn in snakemake.input.networks]
48794867
# Hack the transmission projects
48804868
networks = [
4881-
hack_transmission_projects(n.copy(), _networks[0], int(my), snakemake, costs)
4869+
process_postnetworks(n.copy(), _networks[0], int(my), snakemake, costs)
48824870
for n, my in zip(_networks, modelyears)
48834871
]
48844872

workflow/scripts/plot_ariadne_report.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
path = "../submodules/pypsa-eur/scripts"
2222
sys.path.insert(1, os.path.abspath(path))
2323
from _helpers import configure_logging, set_scenario_config
24-
from export_ariadne_variables import get_discretized_value, hack_transmission_projects
24+
from export_ariadne_variables import get_discretized_value, process_postnetworks
2525
from plot_power_network import load_projection
2626
from plot_summary import preferred_order, rename_techs
2727
from prepare_sector_network import prepare_costs
@@ -1501,7 +1501,7 @@ def plot_elec_map_de(
15011501

15021502
# Hack the transmission projects
15031503
networks = [
1504-
hack_transmission_projects(n.copy(), _networks[0], int(my), snakemake, costs)
1504+
process_postnetworks(n.copy(), _networks[0], int(my), snakemake, costs)
15051505
for n, my in zip(_networks, modelyears)
15061506
]
15071507

0 commit comments

Comments
 (0)