Fix corine bool and offshore keyerror#2113
Conversation
When corine is set to false for offshore technologies, convert it to an empty dict so downstream 'key in corine' checks are skipped. Fixes PyPSA#2111
Filter availability matrix buses against clustered regions index to avoid KeyError when countries' offshore zones are dropped. Fixes PyPSA#2112
There was a problem hiding this comment.
Pull request overview
Fixes two crash scenarios in the renewable availability/profiles pipeline when running offshore technologies with corine: false and/or country lists that lead to offshore regions being dropped during clustering.
Changes:
- Guard
corineconfig parsing indetermine_availability_matrix_MD_UA.pyso non-dict values (e.g.false) don’t break"key" in corinechecks. - Filter offshore region indices against available clustered offshore regions in
build_renewable_profiles.py. - Add a fallback in average-distance calculation to avoid
KeyErrorwhen a bus is missing fromregions.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
scripts/determine_availability_matrix_MD_UA.py |
Adds a type guard to treat non-dict corine config values as “disabled” instead of crashing. |
scripts/build_renewable_profiles.py |
Avoids KeyError for missing offshore buses by intersecting indices and skipping missing buses in distance calculation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| if snakemake.wildcards.technology.startswith("offwind"): | ||
| # for offshore regions, the shortest distance to the shoreline is used | ||
| offshore_regions = availability.coords["bus"].values | ||
| offshore_regions = np.intersect1d(offshore_regions, regions.index) |
There was a problem hiding this comment.
Filtering offshore_regions only when selecting regions leaves availability (and later resource_regions/class_masks) still containing buses that were dropped during clustering. This can produce profiles/potentials for buses that have no corresponding offshore distance geometry and makes outputs inconsistent (e.g. class_regions written only for the filtered bus set). Consider subsetting availability to the same offshore_regions intersection here (and similarly filter resource_regions after loading) so all downstream computations operate on a consistent bus index.
| offshore_regions = np.intersect1d(offshore_regions, regions.index) | |
| offshore_regions = np.intersect1d(offshore_regions, regions.index) | |
| # align availability with the filtered offshore regions to keep a consistent bus index | |
| availability = availability.sel(bus=offshore_regions) |
| for bus, bin in bus_bins: | ||
| if bus not in regions.index: | ||
| average_distance.append(0.0) |
There was a problem hiding this comment.
Appending 0.0 for buses missing from regions.index silently produces a plausible-looking distance and can mask data issues (and leave inconsistent outputs if those buses still have nonzero potential). Prefer to ensure those buses are removed upstream (e.g. by subsetting availability/class_masks to the regions bus set), or use NaN plus a clear warning/error so downstream consumers don’t interpret missing geometry as zero distance.
| for bus, bin in bus_bins: | |
| if bus not in regions.index: | |
| average_distance.append(0.0) | |
| # Identify buses present in the layout but missing geometry in regions | |
| missing_buses = {bus for bus, _ in bus_bins} - set(regions.index) | |
| if missing_buses: | |
| logger.warning( | |
| "Average distance could not be computed for %d bus(es) missing from " | |
| "`regions.index`: %s. Distances for these buses will be set to NaN.", | |
| len(missing_buses), | |
| ", ".join(sorted(map(str, missing_buses))), | |
| ) | |
| for bus, bin in bus_bins: | |
| if bus not in regions.index: | |
| # Mark missing geometry explicitly instead of assuming zero distance | |
| average_distance.append(np.nan) |
When clustering.simplify_network.to_380 is set to false, skip simplify_network_to_380() so that original voltage levels and transformers are preserved in the simplified network.
Add v_nom to custom_line_groupers so lines at different voltage levels are not merged. Pass with_country=True to cluster_regions so the output region shapefiles retain a country column for downstream scripts.
Use the 'country' column (when available) instead of slicing the first two characters of the bus name. Also subset sjoin to geometry-only to avoid extra columns and deduplicate plants in overlapping regions.
Write an empty availability matrix and exit early when no valid region geometries exist. Guard WDPA polygon/point reads behind geometry checks to prevent errors on empty GeoDataFrames.
for more information, see https://pre-commit.ci
Closes #2111 and #2112.
Changes proposed in this Pull Request
Fixes two detected bugs in the renewable availability/profiles pipeline when using offshore technologies with
corine: falseand non-standard country lists:determine_availability_matrix _MD_UA.py: Convertcorineto an empty dict when set to false, preventingTypeErroron"key" in corinechecks.build_renewable_profiles.py: Filter offshore buses against clustered regions index to avoidKeyErrorfor buses dropped during clustering.Used config file: config.osm_eem.yaml
Checklist
pixi.toml(usingpixi add <dependency-name>).config/config.default.yaml.doc/configtables/*.csv.doc/release_notes.rstis added.