Skip to content

Commit 008574f

Browse files
fix: split cost + length for multi-link projects (#793)
* fix: split cost + length for multi-link projects * refactor: rename to investment_attrs_per_line * refactor: move cost + lengt split into an extra fct * docs: add release note * fix: align docstring Co-authored-by: Daniel Rüdt <117752024+daniel-rdt@users.noreply.github.com> --------- Co-authored-by: Daniel Rüdt <117752024+daniel-rdt@users.noreply.github.com>
1 parent 9bfb658 commit 008574f

2 files changed

Lines changed: 70 additions & 31 deletions

File tree

doc/release_notes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
**Bugfixes and Compatibility**
3939

40+
* Fix: split project-level cost and length evenly across lines for multi-link transmission projects, avoiding inflated values ([#793](https://github.com/open-energy-transition/open-tyndp/pull/793)).
41+
4042
* Use `overnight` foresight in MSV network preparation instead of `perfect` ([#813](https://github.com/open-energy-transition/open-tyndp/pull/813)).
4143

4244
* Rename bus for `t339` project (Tyrrhenian) from ITSI to ITVI ([#751](https://github.com/open-energy-transition/open-tyndp/pull/751)).
@@ -93,9 +95,13 @@
9395
## Upcoming PyPSA-Eur Release
9496

9597
* fix: update stale contribution docs (linting and formatting ruff)
98+
9699
* feat: data version CSV / YAML file can be specified separately or extended by the user in the `data.version_files` config entry ([#2016](https://github.com/PyPSA/pypsa-eur/issues/2016)).
100+
97101
* Fix: Resolve plotting crashes from missing `tech_colors` entries by adding `heat dsm` color and implementing upfront validation for missing keys in `plot_summary.py` ([#2108](https://github.com/PyPSA/pypsa-eur/issues/2108)).
102+
98103
* Fix: Retry interrupted WDPA and WDPA-marine downloads ([#2138](https://github.com/PyPSA/pypsa-eur/issues/2138)).
104+
99105
* feat: Make the default target rule configurable (defaults to "all" for backwards compatibility)
100106

101107
* Fix: Keep unset `p_set` (NaN) as NaN when aggregating components in `cluster_heat_buses`, required for [PyPSA#1703](https://github.com/PyPSA/PyPSA/pull/1703).

scripts/cba/clean_projects.py

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -65,36 +65,6 @@
6565
}
6666

6767

68-
def read_tyndp_electricity_buses(buses_fn: str) -> pd.Index:
69-
"""
70-
Read the list of electricity nodes from the TYNDP input data.
71-
72-
Parameters
73-
----------
74-
buses_fn : str
75-
Path to the list of nodes from the TYNDP bundle.
76-
77-
Returns
78-
-------
79-
pd.Index
80-
Electricity buses as used in Open-TYNDP.
81-
82-
See Also
83-
--------
84-
build_tyndp_network.build_buses
85-
"""
86-
buses = pd.Index(
87-
pd.read_excel(buses_fn)
88-
.replace("UK", "GB", regex=True)
89-
.rename({"NODE": "bus_id"}, axis=1)["bus_id"]
90-
)
91-
92-
# Manually add Italian virtual nodes
93-
buses = buses.union(["ITCO", "ITVI"])
94-
95-
return buses
96-
97-
9868
def extract_transmission_projects(
9969
excel_path: Path, existing_buses: pd.Index
10070
) -> pd.DataFrame:
@@ -343,6 +313,64 @@ def build_method_assignments(
343313
return projects.merge(assigned, on="project_id", how="left")
344314

345315

316+
def read_tyndp_electricity_buses(buses_fn: str):
317+
"""
318+
Read node list for electricity from tyndp data input.
319+
320+
Parameters
321+
----------
322+
- buses_fn (str): Path to "LIST OF NODES.xlsx" from tyndp bundle
323+
324+
Returns
325+
-------
326+
- buses: Index of electricity buses as used in Open-TYNDP
327+
328+
See Also
329+
--------
330+
build_tyndp_network.py : build_buses
331+
"""
332+
buses = pd.Index(
333+
pd.read_excel(buses_fn)
334+
.replace("UK", "GB", regex=True)
335+
.rename({"NODE": "bus_id"}, axis=1)["bus_id"]
336+
)
337+
338+
# Manually add Italian virtual nodes
339+
buses = buses.union(["ITCO", "ITVI"])
340+
341+
return buses
342+
343+
344+
def split_investment_attributes_per_line(
345+
investment_attrs: pd.DataFrame, transmission_projects: pd.DataFrame
346+
) -> pd.DataFrame:
347+
"""
348+
Split investment costs and length evenly across transmission lines.
349+
350+
Investment costs and length are given per project and not per
351+
transmission line, therefore these attributes need to be split before
352+
merging.
353+
354+
Parameters
355+
----------
356+
investment_attrs : pd.DataFrame
357+
Investment attributes indexed by project_id.
358+
transmission_projects : pd.DataFrame
359+
Transmission projects with a project_id column.
360+
361+
Returns
362+
-------
363+
pd.DataFrame
364+
investment_attrs with length_km and capex_meur divided by the number
365+
of lines per project.
366+
"""
367+
link_counts = transmission_projects.groupby("project_id").size()
368+
return investment_attrs.assign(
369+
length_km=lambda d: d.length_km / d.index.map(link_counts).fillna(1),
370+
capex_meur=lambda d: d.capex_meur / d.index.map(link_counts).fillna(1),
371+
)
372+
373+
346374
if __name__ == "__main__":
347375
if "snakemake" not in globals():
348376
from scripts._helpers import mock_snakemake
@@ -361,8 +389,13 @@ def build_method_assignments(
361389
transmission_projects = extract_transmission_projects(excel_path, existing_buses)
362390

363391
investment_attrs = extract_investment_attributes(excel_path)
392+
393+
investment_attrs_per_line = split_investment_attributes_per_line(
394+
investment_attrs, transmission_projects
395+
)
396+
364397
transmission_projects = transmission_projects.merge(
365-
investment_attrs, on="project_id", how="left"
398+
investment_attrs_per_line, on="project_id", how="left"
366399
)
367400

368401
transmission_projects.to_csv(snakemake.output.transmission_projects, index=False)

0 commit comments

Comments
 (0)