Skip to content

Enable global applicability - #8

Open
ekatef wants to merge 54 commits into
mainfrom
integrate-composite-features
Open

ekatef wants to merge 54 commits into
mainfrom
integrate-composite-features

Conversation

@ekatef

@ekatef ekatef commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

The PR brings in functionality to enable accuracy of GridBuilder when being applied to any country of the world.

Disclaimer

The implementation is build an a combination of PyPSA-Earth approach with learnings from the regional grid studies conducted during previous year by PyPSA-meets-Earth and MapYourGrid initiatives. I have updated the authors list accordingly, though it is not exhaustive yet.

Major changes

  1. Restore country field since it is crucial for correct assignment of conductor types. Bring-in regional line types #7 provides more details on that.
  2. Improved reliability and accuracy of the parameters clean-up according to results of the global grid-building runs.
  3. Enhanced treatment of the frequency field to enable generalisation.
  4. Increase reliability for non-perfect data, specifically for the countries where some of the data features can be missing.
  5. Added connections with the data-producing initiatives on which the project builds up.
  6. Enable usage of custom data.
  7. Added treatment of DC lines using a combination of PyPSA-Earth experience with the relation concept proposed in PyPSA-Eur.
  8. Bug-fixing, removal of hard-coding and human proof-read of the documentation.

Reviewer checklist

  • There are no pip dependencies in the module's environment files (workflow/envs/).
  • All rules use pathvars (e.g., <results>) in their inputs and outputs.
  • The integration test-suite is successful, including:
    • pre-commit.ci tests pass.
    • tests pass for all relevant OS configurations (linux, osx, windows).
  • Module documentation is up-to-date, including:
    • INTERFACE.yaml mentions all relevant pathvars and wildcards.
    • README.md describes how to use the module and has the necessary citations.

@ekatef
ekatef requested a review from davide-f September 27, 2026 08:38
@ekatef

ekatef commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator Author

@davide-f it would be good to have your looks on that. The major goal of this PR is to enable global applicability of GridBuilder creating a base to port results of this base if the regional grid modelling studies from global grid modelling.

To facilitate generalisation, it can be handy to use composite_clean_build branch which has been created to incorporate into PyPSA-Eath grid modelling the approaches amended to it in PyPSA-Eur.

@davide-f

Copy link
Copy Markdown
Collaborator

Thanks Katia! This is to confirm that I'm going through it. The work is quite extensive and I'll need a few days to complete it

@ekatef

ekatef commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

A technical note: GridBuilder needs some technical fixes right now to enable compatibility with modelblocks. To facilitate things, it would be good to fix #4 first before merging this PR.

@davide-f davide-f left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, nice extension to the DC! Comments follow.
It would be great to see two tests for example one image for Italy and one for Congo to see how the DC systems are rendered in the two systems.

Cross-linking this comment related to this PR #6 (comment)


@field_validator("files")
@classmethod
def validate_file_names(cls, v: list[str]) -> list[str]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the filename convenction necessary?

I'd recommend to include a validation of the minimum required columns of the files to ensure consistency with OSM-retrieved data

frame: gpd.GeoDataFrame,
name: str,
color: list[int] | str,
*,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this wanted? It makes sense for robustness of the code


_VALID_REGIONS: frozenset[str] = frozenset(get_all_valid_codes())

#: The fixed set of raw OSM features to enable compartibility with custom data.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#: The fixed set of raw OSM features to enable compartibility with custom data.
# The fixed set of raw OSM features to enable compatibility with custom data.



def _merge_country_codes(values: Any) -> str:
"""Clean-up country codes for multy-country entries.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Clean-up country codes for multy-country entries.
"""Clean-up country codes for multi-country entries.

Please improve description to describe how codes are cleaned

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For lines, it would be interesting to have country0 and country1 denoting the country of the endings. Can be an issue for future PRs

Comment on lines +67 to +68
# earth: repl_circuits. "2/3" and "2-1" would strip to 23 and 21.
- exact: ["2/3", "2"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unsure of this. It would be worth to comment it and add a TODO to check it

return all_transformers[["transformer_id", *columns]]


def _add_converters(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend improving the docstrings and describe the approach.
That helps also understanding what priorities to give when adopting a common solution.

(ac_buses["voltage"] - dc_bus["voltage"]).abs().idxmin()
]
pairing = "same_station"
elif station_id in converter_stations:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if/elif condition defines a priority order that needs better documentation

Comment thread workflow/scripts/clean.py
Comment on lines +517 to +527
# An explicit zero means the way carries no live conductor: a ground wire
# ("ground") or a retired one ("1 disused"). Every branch below floors the
# count at one circuit, so without this the way would enter the network as
# a live single-circuit line. PyPSA-Earth reaches the same end by letting
# the zero through and dropping it in filter_circuits.
bool_no_conductors = (~df_lines["cleaned"]) & (
((df_lines["cables"] == "0") & (df_lines["circuits"] == ""))
| (df_lines["circuits"] == "0")
)
df_lines.loc[bool_no_conductors, "circuits"] = "0"
df_lines.loc[bool_no_conductors, "cleaned"] = True

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you identified such cases in OSM data?

Comment thread workflow/scripts/clean.py
Comment on lines +1192 to +1196
"""Minimum AC voltage [V] for ``country``: its regional override, else the network default.

For a cross-border element the most permissive threshold wins, so an
interconnector survives whenever either side would keep it.
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may not need the overcomplication of a minimum voltage by country, rather one value for each execution. This is not a hard comment though

# point at the same voltage must not share a bus.
endpoints = (
endpoints.groupby(["voltage", "geometry"])
endpoints.groupby(["voltage", "dc", "geometry"])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As endpoints also depend on ac/dc, their bus_id may change accordingly. The risk is that AC and DC systems may have the same ID otherwise

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants