Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
42e2dbd
Added new transmission key to config, schema and docs. Implemented in…
bobbyxng Apr 17, 2026
44320a7
Fix pre-commit issues, trailing whitespaces, etc.
bobbyxng Apr 17, 2026
3d1d3f5
Updated description to include detailed output/coluns.
bobbyxng Apr 17, 2026
65d1b0f
renamed build_transmission to build_transmission_topology
bobbyxng Apr 20, 2026
a908726
Implemented new config for H2 pipelines.
bobbyxng Apr 20, 2026
e3bd7f5
Implemented new key for CO2 networks.
bobbyxng Apr 20, 2026
67c2c58
Bug fix snakemake.
bobbyxng Apr 20, 2026
e2d9445
Missing trailing :
bobbyxng Apr 20, 2026
590e5b1
fix: added cf_transmission to add_existing_baseyear.
bobbyxng Apr 21, 2026
2d8bf6f
Moved electricity transmission and transmission limit to transmission.
bobbyxng Apr 21, 2026
164b56f
Moved base_network config to transmission.
bobbyxng Apr 21, 2026
bcd519d
Pre-commit hooks
bobbyxng Apr 21, 2026
33bc0da
Added lines, links, transformers, transmission_projects (now projects…
bobbyxng Apr 21, 2026
6adb27d
Added gas_network (now methane_gas) to transmission key.
bobbyxng Apr 21, 2026
833260f
Renamed methane_gas back to gas.
bobbyxng Apr 22, 2026
a2ecf3d
Merge branch 'master' into new-transmission
bobbyxng Apr 23, 2026
ec5756f
Refactored code do build transmission topology based on min_degrees i…
bobbyxng Apr 23, 2026
0712c91
Added prefix electricity_ to rules/scripts/docs of add_transmission_p…
bobbyxng Apr 23, 2026
2b3ce21
Snakemake 'run' wildcard fix.
bobbyxng Apr 23, 2026
21925e8
Added max_offshore_haversine_distance key per transmission carrier (i…
bobbyxng Apr 23, 2026
06198f6
Added to schema/validation.
bobbyxng Apr 23, 2026
c123c92
Moved distribution grid into new transmission key 'electricity_distri…
bobbyxng Apr 24, 2026
2f3cbf8
Moved carrier-specific transmission efficiencies into the new subsect…
bobbyxng Apr 24, 2026
d050860
Renamed gas_distribution_grid to *_cost, as they do not actually add …
bobbyxng Apr 24, 2026
30ba3f4
H2 retrofit moved to transmission.hydrogen. Clean-up of params.
bobbyxng Apr 24, 2026
87e1323
Bug fix in solve_overnight.smk params and added release notes.
bobbyxng Apr 24, 2026
1e1d52f
Clean up mock snakemakes.
bobbyxng Apr 24, 2026
29ea909
Implemented review comments, splitting into two rules, config call cl…
bobbyxng Apr 27, 2026
00d1c7d
Updated schema.
bobbyxng Apr 27, 2026
1768e73
Reduce to topology feature without breaking config changes
fneum Oct 6, 2026
a2f39cf
Merge remote-tracking branch 'origin/master' into pr-2153
fneum Oct 6, 2026
85d23c5
docs: document pipeline candidate rules and topology change
fneum Oct 6, 2026
f31e62c
Simplify candidate topology into one rule and script
fneum Oct 6, 2026
bf7c2da
Merge remote-tracking branch 'origin/master' into pipeline-topology-d…
fneum Nov 3, 2026
22e7a97
Per-carrier transport corridors, biomass transport and review fixes
fneum Nov 3, 2026
88f1f8d
Merge branch 'master' into pipeline-topology-delaunay
bobbyxng Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/config.default.yaml
Comment thread
bobbyxng marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,16 @@ sector:
CO2 pipeline:
efficiency_per_1000km: 1
H2_network: true
transport_corridors:
H2:
min_degree: 1
max_offshore_distance: .inf
CO2:
min_degree: 1
max_offshore_distance: .inf
biomass:
min_degree: 1
max_offshore_distance: .inf
gas_network: true
H2_retrofit: false
H2_retrofit_capacity_per_CH4: 0.6
Expand Down
185 changes: 185 additions & 0 deletions config/schema.default.json
Original file line number Diff line number Diff line change
Expand Up @@ -5725,6 +5725,62 @@
"description": "Add option for new hydrogen pipelines.",
"type": "boolean"
},
"transport_corridors": {
"description": "Configuration for `sector.transport_corridors` settings.",
"properties": {
"H2": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"CO2": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"biomass": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
}
}
},
"gas_network": {
"default": true,
"description": "Add existing natural gas infrastructure, incl. LNG terminals, production and entry-points. The existing gas network is added with a lossless transport model. A length-weighted `k-edge augmentation algorithm <https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.connectivity.edge_augmentation.k_edge_augmentation.html#networkx.algorithms.connectivity.edge_augmentation.k_edge_augmentation>`_ can be run to add new candidate gas pipelines such that all regions of the model can be connected to the gas network. When activated, all the gas demands are regionally disaggregated as well.",
Expand Down Expand Up @@ -7346,6 +7402,23 @@
"grid_codes"
]
},
"_CorridorConfig": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"_CutoutConfig": {
"description": "Configuration for a single cutout in `atlite.cutouts`.",
"properties": {
Expand Down Expand Up @@ -9750,6 +9823,62 @@
}
}
},
"_TransportCorridorsConfig": {
"description": "Configuration for `sector.transport_corridors` settings.",
"properties": {
"H2": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"CO2": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"biomass": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
}
}
},
"_UserAgentConfig": {
"description": "Configuration for `overpass_api.user_agent` settings.",
"properties": {
Expand Down Expand Up @@ -13189,6 +13318,62 @@
"description": "Add option for new hydrogen pipelines.",
"type": "boolean"
},
"transport_corridors": {
"description": "Configuration for `sector.transport_corridors` settings.",
"properties": {
"H2": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"CO2": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
},
"biomass": {
"description": "Configuration for the candidate corridors of one carrier.",
"properties": {
"min_degree": {
"default": 1,
"description": "Minimum number of candidate corridors per region. The candidates start from the Gabriel graph and add the shortest Delaunay edges until each region reaches this degree. Set to 0 to use the full Delaunay graph.",
"minimum": 0,
"type": "integer"
},
"max_offshore_distance": {
"default": null,
"description": "Maximum offshore length of a candidate corridor (km). Defaults to unlimited (`.inf`).",
"exclusiveMinimum": 0,
"type": "number"
}
}
}
}
},
"gas_network": {
"default": true,
"description": "Add existing natural gas infrastructure, incl. LNG terminals, production and entry-points. The existing gas network is added with a lossless transport model. A length-weighted `k-edge augmentation algorithm <https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.connectivity.edge_augmentation.k_edge_augmentation.html#networkx.algorithms.connectivity.edge_augmentation.k_edge_augmentation>`_ can be run to add new candidate gas pipelines such that all regions of the model can be connected to the gas network. When activated, all the gas demands are regionally disaggregated as well.",
Expand Down
2 changes: 2 additions & 0 deletions doc/design/biomass.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ counts as negative emissions when it is sequestered, see
Solid biomass can be one European pool or regionally resolved. When resolved,
transport between regions can be free or priced per distance with
country-specific costs, which reflects road transport of bulky feedstocks.
Priced transport follows the same candidate corridors as new
[hydrogen pipelines](hydrogen.md#transport).
Biogas follows the gas network if that is resolved.

## Further reading
Expand Down
6 changes: 4 additions & 2 deletions doc/design/carbon-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ larger and far from settlements, and onshore formations as well.
## Transport

CO~2~ can be transported in a pipeline network between regions, onshore and
submarine, whose capacity is optimised, with candidate routes following the
existing electricity network. An optional compression stage with its
submarine, whose capacity is optimised, with the same Delaunay-based candidate
corridors as new [hydrogen pipelines](hydrogen.md#transport). The submarine
share of each corridor is the share of its straight line that crosses
offshore regions. An optional compression stage with its
electricity demand can be added for transport in dense phase. Alternatively
CO~2~ is copperplated, with a transport and storage cost per tonne. Venting
captured CO~2~ back to the atmosphere can be allowed as an escape valve.
Expand Down
12 changes: 9 additions & 3 deletions doc/design/hydrogen.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ constraint is usually where caverns exist, not how much they can hold.

## Transport

Hydrogen moves through pipelines. New pipelines can be built along corridors
where an electricity or gas connection exists today. Optionally, existing gas
pipelines can be retrofitted [@gasforclimateEuropeanHydrogen2020], which is
Hydrogen moves through pipelines. New pipelines can be built along candidate
corridors between neighbouring regions and along existing gas pipelines if the
gas network is modelled. The corridors come from a Delaunay triangulation of
the regions, by default reduced to its Gabriel graph, which keeps a direct
link only if no third region lies within the circle spanned by it. Regions
left with too few corridors receive their shortest remaining links, and
corridors can be limited in their offshore length. The same method gives the
corridors for CO~2~ pipelines and biomass transport, each with its own
settings. Optionally, existing gas pipelines can be retrofitted [@gasforclimateEuropeanHydrogen2020], which is
cheaper but tied to the gas network: for every unit of gas capacity taken out
of service, a fixed share becomes available for hydrogen on the same route.
If the gas network is not resolved regionally, the retrofit option still
Expand Down
1 change: 1 addition & 0 deletions doc/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

<!-- Upcoming Release -->
<!-- ================= -->
* Candidate corridors for new hydrogen and carbon dioxide pipelines and for biomass transport now come from a Delaunay triangulation of the regions instead of the electricity grid, with settings per carrier under `sector: transport_corridors`. This changes default results ([#2351](https://github.com/PyPSA/pypsa-eur/pull/2351)).

* **Breaking:** Removed the integration of the discontinued OETC service. A non-empty `solving: oetc:` section in the config now raises an error ([#2398](https://github.com/PyPSA/pypsa-eur/pull/2398)).
* Fix: Runs with only landlocked countries and offshore technologies disabled work again, which broke in [#2169](https://github.com/PyPSA/pypsa-eur/pull/2169). Renewable capacity estimation now skips carriers missing from `electricity: renewable_carriers` ([#2378](https://github.com/PyPSA/pypsa-eur/pull/2378)).
Expand Down
4 changes: 4 additions & 0 deletions doc/rules/carriers.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ management](../design/carbon-management.md) in the design section.

{{ rules("build_gas_network", "build_gas_input_locations", "cluster_gas_network", "build_salt_cavern_potentials") }}

## Transport corridors

{{ rules("build_transmission_topology") }}

## Carbon sequestration

{{ rules("build_co2_sequestration_potentials", "build_clustered_co2_sequestration_potentials") }}
19 changes: 19 additions & 0 deletions rules/build_sector.smk
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,25 @@ rule cluster_gas_network:
scripts("cluster_gas_network.py")


rule build_transmission_topology:

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 compatible with the scenario manager, shared resources? In case two scenarios differ in pipeline topology?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

should work, they just need to put it under run: shared_resources: exclude

"""Builds candidate corridors for H2, CO2 and biomass transport from the Delaunay graph of regions."""
input:
network=resources("networks/clustered.nc"),
offshore_shapes=resources("offshore_shapes.geojson"),
output:
candidates=resources("transmission_candidates.geojson"),
log:
logs("build_transmission_topology.log"),
benchmark:
benchmarks("build_transmission_topology")
resources:
mem_mb=2000,
params:
transport_corridors=config_provider("sector", "transport_corridors"),
script:
scripts("build_transmission_topology.py")


rule build_daily_heat_demand:
"""Builds daily heat demand time series per region from cutout temperatures and population."""
input:
Expand Down
1 change: 1 addition & 0 deletions rules/compose.smk
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def get_compose_inputs(w):
if sector["gas_network"] or {"gas", "H2"} & set(import_carriers)
else []
),
transmission_candidates=rules.build_transmission_topology.output.candidates,
pop_weighted_energy_totals=resources("pop_weighted_energy_totals.csv"),
pop_weighted_heat_totals=(
resources("pop_weighted_heat_totals.csv") if sector["heating"] else []
Expand Down
Loading
Loading