Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
62f0be5
create streamlining plan
FabianHofmann Jul 14, 2025
1369853
update plan
FabianHofmann Jul 15, 2025
16bdb75
Implement streamlined workflow test framework
FabianHofmann Jul 16, 2025
685e168
Refine implementation plan based on successful testing
FabianHofmann Jul 20, 2025
29199b1
Merge branch 'master' into streamline-workflow
FabianHofmann Jul 23, 2025
051060d
Implement streamlined workflow with compose_network.py
FabianHofmann Jul 23, 2025
a1183df
Fix critical issues in streamlined workflow implementation
FabianHofmann Jul 23, 2025
03c875f
Fix cluster wildcard and resource path issues
FabianHofmann Jul 23, 2025
cbd8328
Use config_provider and resources functions consistently
FabianHofmann Jul 23, 2025
7f2ef1a
add streamlined configs
FabianHofmann Aug 14, 2025
279b017
refac: brute force rename paths, remove wildcards, consolidate solve …
FabianHofmann Aug 16, 2025
a7670ec
refac: update paths across snakefiles
FabianHofmann Aug 16, 2025
c81163d
first stable dag with compose rule
FabianHofmann Aug 16, 2025
e872f02
revert temporal config key
FabianHofmann Sep 17, 2025
2fd3b0b
fix: disinguish base and clustered regions
FabianHofmann Sep 22, 2025
1be0432
refac: use "simplified.nc" for simplified network stage
FabianHofmann Sep 25, 2025
4410a3c
feat: make compose_network work
FabianHofmann Sep 28, 2025
4380c25
feat: add sector mode to only add components needed in the electricit…
FabianHofmann Sep 28, 2025
b625b8c
feat: sanitize busmap
FabianHofmann Sep 29, 2025
b08e681
Tighten compose configuration requirements
FabianHofmann Sep 29, 2025
ee33eab
feat: pull over feats from add_existing_baseyear and add_brownfield
FabianHofmann Sep 30, 2025
0ca08c8
feat: port cap_transmission_capacity and enforce_autarky to streamlin…
FabianHofmann Sep 30, 2025
341064a
refac: modularize logics in compose_network
FabianHofmann Sep 30, 2025
ee5097f
follow up
FabianHofmann Sep 30, 2025
2d32e77
feat: port renewable capacity limit adjustment to compose_network
FabianHofmann Sep 30, 2025
7b8b97f
tiny fixes
FabianHofmann Oct 13, 2025
3e9d744
refac: apply temporal clustering before base year addition
FabianHofmann Oct 13, 2025
40d8088
fix: only run ptes update if dataframe is not empty
FabianHofmann Oct 13, 2025
fac1d2c
add concatenation logic for multi invest optimization
FabianHofmann Oct 15, 2025
3054234
only trigger last horizon in collection rule
FabianHofmann Oct 15, 2025
0928db1
Merge branch 'master' into streamline-workflow
FabianHofmann Oct 15, 2025
43847a2
fix: multi-period optimization and composition
FabianHofmann Oct 19, 2025
5be0961
fix: myopic make test
FabianHofmann Oct 20, 2025
180137e
fix: reduce number of levels in summary files
FabianHofmann Oct 20, 2025
5c919fe
Merge branch 'master' into streamline-workflow
FabianHofmann Oct 21, 2025
4505e79
support electricity-only with myopic foresight
FabianHofmann Oct 20, 2025
abb081d
make summary rule compatible with electricity only
FabianHofmann Oct 20, 2025
0365a46
update pypsa version
FabianHofmann Oct 23, 2025
358ab9f
streamline workflow: cleanup and pypsa 1.0 compatibility
FabianHofmann Oct 23, 2025
b390176
remove dead code from old wildcard workflow
FabianHofmann Oct 23, 2025
c09400b
add migration documentation for streamlined workflow
FabianHofmann Oct 24, 2025
cdf9737
document critical gaps in perfect foresight implementation
FabianHofmann Oct 24, 2025
91f4d7e
implement critical perfect foresight features
FabianHofmann Oct 24, 2025
430f68c
restore investment weightings and add temporal aggregation validation
FabianHofmann Oct 24, 2025
e9ca903
move perfect foresight functions to prepare_perfect_foresight.py
FabianHofmann Oct 27, 2025
05f7f99
fix perfect foresight workflow dependencies
FabianHofmann Oct 28, 2025
459b5e4
use NetworkCollection for myopic summary generation
FabianHofmann Oct 28, 2025
d146f4f
integrate cumulative costs calculation into make_summary
FabianHofmann Oct 28, 2025
61bba00
fix: include all plot_summary outputs in CORE_OUTPUTS
FabianHofmann Oct 28, 2025
ecbf354
adjust plotting thresholds in test configs for better visibility
FabianHofmann Oct 28, 2025
dadda51
consolidate graphics/ to graphs/ directory
FabianHofmann Oct 28, 2025
cd523fb
add electricity foresight tests and fix carbon budget plot error hand…
FabianHofmann Oct 28, 2025
853b3b5
fix: correctly apply sn weightings in perfect concat
FabianHofmann Oct 29, 2025
8414d3e
fix: add auto-scaling support for plot axes in test configs
FabianHofmann Oct 29, 2025
e3f5ccd
docs: complete migration guide and refactor sector config to nested s…
FabianHofmann Nov 3, 2025
a437328
remove internal doc file [skip CI]
FabianHofmann Nov 3, 2025
735f362
add get_config function to get full scenario aware config
FabianHofmann Nov 4, 2025
a072121
refac: harmonize co2 budget allocation
FabianHofmann Nov 11, 2025
e567128
refac: streamline compose_network by removing InputFiles dataclass
FabianHofmann Nov 11, 2025
47df995
delete unneeded file
FabianHofmann Nov 11, 2025
9e175e3
refactor config access in compose inputs
FabianHofmann Nov 11, 2025
1b12584
Fix outdated expression for 'transmission_limit' (#1894)
Parisra Nov 10, 2025
324f05b
Add option to set minimum unit dispatch for electrolysis (#1859)
millingermarkus Nov 1, 2025
bcfafa7
refactor: use snapshot_weightings to define nyears in build_transport…
tgilon Oct 31, 2025
70a44d9
chore(deps): bump the github-actions group with 2 updates (#1870)
dependabot[bot] Nov 1, 2025
08d5cc1
Merge branch 'master' into merge-master-into-streamline
FabianHofmann Nov 11, 2025
a6f5bff
fix unit tests
FabianHofmann Nov 12, 2025
d3684f5
follow up
FabianHofmann Nov 12, 2025
7543d0e
follow up
FabianHofmann Nov 12, 2025
bcca49b
improve deprecation warnings; follow up on powerplant renaming
FabianHofmann Nov 13, 2025
9083f09
update doc
FabianHofmann Nov 18, 2025
b95b959
streamline mock_snakemake calls across scripts
FabianHofmann Nov 20, 2025
a67cc56
Merge latest master into streamline workflow branch
FabianHofmann Nov 24, 2025
d64e53f
Merge branch 'master' into streamline-workflow
FabianHofmann Nov 24, 2025
94e8ea1
update pixi toml and CI tests
FabianHofmann Nov 24, 2025
b7b3514
unify temporal resolution config: merge resolution_elec/resolution_se…
FabianHofmann Nov 24, 2025
c77f944
fix: adjust s_nom_max limit
FabianHofmann Nov 25, 2025
e3a5899
update pixi toml rules
FabianHofmann Nov 25, 2025
0b888d7
refac: use sector inputs only if sector coupling is enabled
FabianHofmann Nov 25, 2025
d30a7a1
unify CO2 constraints: remove legacy co2limit in favor of co2_budget
FabianHofmann Nov 25, 2025
b603709
remove deprecated opts/sector_opts wildcard documentation
FabianHofmann Nov 25, 2025
86ba87b
fix: add missing top-level planning_horizons to TYNDP test config
FabianHofmann Nov 26, 2025
f314d3e
resolve merge: integrate new dataset versioning system
FabianHofmann Dec 8, 2025
e3a1429
fix: update test configs for streamlined workflow
FabianHofmann Dec 8, 2025
7ffb54f
fix: heat profile reference
FabianHofmann Dec 8, 2025
579f07c
Merge branch 'master' into streamline-workflow
fneum Dec 10, 2025
8020c25
Simplify CO2 budget constraints
FabianHofmann Dec 14, 2025
21bf7f2
Merge branch 'master' into streamline-workflow
FabianHofmann Jan 21, 2026
f580fd5
Update config/test/config.myopic.yaml
FabianHofmann Jan 21, 2026
e3b72fd
udpate co2 config
FabianHofmann Jan 21, 2026
5cc2970
revert some config changes
FabianHofmann Jan 21, 2026
dbe46b6
Update scripts/make_summary.py
FabianHofmann Jan 21, 2026
19cfd5e
Update doc/release_notes.rst
FabianHofmann Jan 21, 2026
4a13f94
adress more comments in config and release notes
FabianHofmann Jan 21, 2026
b78b708
Update doc/release_notes.rst
FabianHofmann Jan 21, 2026
eec0fea
Update doc/migration.rst
FabianHofmann Jan 21, 2026
8bf9275
update configuration.rst
FabianHofmann Jan 21, 2026
8da4043
follow-up: adress review comment
FabianHofmann Jan 21, 2026
f5c91c0
follow up
FabianHofmann Jan 21, 2026
4eb0f25
follow up
FabianHofmann Jan 21, 2026
9c71949
address comments; follow up
FabianHofmann Jan 22, 2026
3a2296c
follow up
FabianHofmann Jan 22, 2026
2f39747
follow up (dirty state)
FabianHofmann Jan 23, 2026
0124d95
follow up
FabianHofmann Jan 25, 2026
c3cf1f0
update doc refs
FabianHofmann Jan 25, 2026
419bc00
follow up - reduced diff
FabianHofmann Jan 25, 2026
8f92e36
udpate migration guide and make some fixes
FabianHofmann Jan 30, 2026
6d88212
small fixes
FabianHofmann Jan 30, 2026
6db1a49
Merge branch 'master' into streamline-workflow
FabianHofmann Feb 2, 2026
6c61c68
Restore job list and workflow graph in sector tutorial
FabianHofmann Feb 2, 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
2 changes: 1 addition & 1 deletion .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
"
graphs/energy.svg
graphs/costs.svg
graphs/balances-energy.svg
graphs/balances_energy.svg
graphs/balances-urban_central_heat.svg
graphs/balances-urban_decentral_heat.svg
graphs/balances-rural_heat.svg
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ CLAUDE.md
.claude/
.github/copilot-instructions.md
CLAUDE.local.md
.envrc
AGENTS.md
# pixi environments
.pixi/*
!.pixi/config.toml
270 changes: 128 additions & 142 deletions Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ from scripts._helpers import (
get_shadow,
path_provider,
)
from scripts.lib.validation.config import validate_config
from scripts.lib.validation.config import normalize_config, validate_config


configfile: "config/config.default.yaml"
Expand All @@ -31,7 +31,8 @@ if Path("config/config.yaml").exists():
configfile: "config/config.yaml"


validate_config(config)
validated = validate_config(config)
normalize_config(config, validated)

run = config["run"]
scenarios = get_scenarios(run)
Expand All @@ -41,9 +42,24 @@ shadow_config = get_shadow(run)
shared_resources = run["shared_resources"]["policy"]
exclude_from_shared = run["shared_resources"]["exclude"]
logs = path_provider("logs/", RDIR, shared_resources, exclude_from_shared)
benchmarks = path_provider("benchmarks/", RDIR, shared_resources, exclude_from_shared)
_benchmark_provider = path_provider(
"benchmarks/", RDIR, shared_resources, exclude_from_shared
)
resources = path_provider("resources/", RDIR, shared_resources, exclude_from_shared)


def benchmarks(fn):
"""Return a benchmark file path, even if legacy directories already exist."""

path = Path(_benchmark_provider(fn))
if path.is_dir():
# Preserve existing benchmark directories by placing the file inside.
path = path / "benchmark.tsv"
elif not path.suffix:
path = path.with_suffix(".tsv")
return str(path)


RESULTS = "results/" + RDIR


Expand All @@ -52,10 +68,7 @@ localrules:


wildcard_constraints:
clusters="[0-9]+(m|c)?|all|adm",
opts=r"[-+a-zA-Z0-9\.]*",
sector_opts=r"[-+a-zA-Z0-9\.\s]*",
planning_horizons=r"[0-9]{4}",
horizon=r"[0-9]{4}",


include: "rules/common.smk"
Expand All @@ -69,157 +82,130 @@ include: "rules/collect.smk"
include: "rules/retrieve.smk"
include: "rules/build_electricity.smk"
include: "rules/build_sector.smk"
include: "rules/solve_electricity.smk"
include: "rules/compose.smk"
include: "rules/solve.smk"
include: "rules/postprocess.smk"
include: "rules/development.smk"


if config["foresight"] == "overnight":

include: "rules/solve_overnight.smk"
# Define output categories based on foresight mode
# This follows the same pattern as postprocess.smk for consistency

# Core outputs that always run
CORE_OUTPUTS = [
RESULTS + "graphs/costs.svg",
RESULTS + "graphs/energy.svg",
RESULTS + "graphs/balances_energy.svg",
]

# Network and timeseries plots (excluded for perfect foresight)
if config["foresight"] != "perfect":
Comment thread
FabianHofmann marked this conversation as resolved.
NETWORK_PLOT_OUTPUTS = [
resources("maps/base_network.pdf"),
resources("maps/clustered_network.pdf"),
RESULTS + "maps/static/power_network_{horizon}.pdf",
RESULTS + "graphs/cop_profiles_{horizon}.html",
]
TIMESERIES_OUTPUTS = [
RESULTS + "graphs/balance_timeseries_{horizon}",
RESULTS + "graphs/heatmap_timeseries_{horizon}",
]
else:
NETWORK_PLOT_OUTPUTS = []
TIMESERIES_OUTPUTS = []

# Myopic-specific outputs
if config["foresight"] == "myopic":
MYOPIC_OUTPUTS = [RESULTS + "csvs/cumulative_costs.csv"]
else:
MYOPIC_OUTPUTS = []


def get_sector_network_plots(w):
"""Returns sector-specific network plots if enabled and not perfect foresight."""
if config["foresight"] == "perfect":
return []

plots = []
if config_provider("sector", "H2_network")(w):
plots.extend(
expand(
RESULTS + "maps/static/h2_network_{horizon}.pdf",
horizon=config["planning_horizons"],
run=config["run"]["name"],
)
)
if config_provider("sector", "gas_network")(w):
plots.extend(
expand(
RESULTS + "maps/static/ch4_network_{horizon}.pdf",
horizon=config["planning_horizons"],
run=config["run"]["name"],
)
)
return plots


if config["foresight"] == "myopic":
def get_balance_map_plots(w):
"""Returns balance map plots (static + interactive) if configured and not perfect foresight."""
if config["foresight"] == "perfect":
return []

include: "rules/solve_myopic.smk"
plots = []

# Static balance maps (PDF)
static_carriers = config_provider("plotting", "balance_map", "bus_carriers")(w)
if static_carriers:
plots.extend(
expand(
RESULTS + "maps/static/balance_map_{carrier}_{horizon}.pdf",
horizon=config["planning_horizons"],
run=config["run"]["name"],
carrier=static_carriers,
)
)

if config["foresight"] == "perfect":
# Interactive balance maps (HTML)
interactive_carriers = config_provider(
"plotting", "balance_map_interactive", "bus_carriers"
)(w)
if interactive_carriers:
plots.extend(
expand(
RESULTS + "maps/interactive/balance_map_{carrier}_{horizon}.html",
horizon=config["planning_horizons"],
run=config["run"]["name"],
carrier=interactive_carriers,
)
)

include: "rules/solve_perfect.smk"
return plots


rule all:
input:
expand(RESULTS + "graphs/costs.svg", run=config["run"]["name"]),
expand(resources("maps/power-network.pdf"), run=config["run"]["name"]),
expand(
resources("maps/power-network-s-{clusters}.pdf"),
run=config["run"]["name"],
**config["scenario"],
),
expand(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}-costs-all_{planning_horizons}.pdf",
run=config["run"]["name"],
**config["scenario"],
),
# COP profiles plots
expand(
RESULTS + "graphs/cop_profiles_s_{clusters}_{planning_horizons}.html",
run=config["run"]["name"],
**config["scenario"],
),
lambda w: expand(
(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}-h2_network_{planning_horizons}.pdf"
if config_provider("sector", "H2_network")(w)
else []
),
run=config["run"]["name"],
**config["scenario"],
),
lambda w: expand(
(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}-ch4_network_{planning_horizons}.pdf"
if config_provider("sector", "gas_network")(w)
else []
),
run=config["run"]["name"],
**config["scenario"],
),
lambda w: expand(
(
RESULTS + "csvs/cumulative_costs.csv"
if config_provider("foresight")(w) == "myopic"
else []
),
run=config["run"]["name"],
),
expand(
RESULTS
+ "graphics/balance_timeseries/s_{clusters}_{opts}_{sector_opts}_{planning_horizons}",
run=config["run"]["name"],
**config["scenario"],
),
expand(
RESULTS
+ "graphics/heatmap_timeseries/s_{clusters}_{opts}_{sector_opts}_{planning_horizons}",
run=config["run"]["name"],
**config["scenario"],
),
# Explicitly list heat source types for temperature maps
lambda w: expand(
(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}_{planning_horizons}-heat_source_temperature_map_river_water.html"
if config_provider("plotting", "enable_heat_source_maps")(w)
and "river_water"
in config_provider("sector", "heat_pump_sources", "urban central")(w)
else []
),
**config["scenario"],
run=config["run"]["name"],
),
lambda w: expand(
(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}_{planning_horizons}-heat_source_temperature_map_sea_water.html"
if config_provider("plotting", "enable_heat_source_maps")(w)
and "sea_water"
in config_provider("sector", "heat_pump_sources", "urban central")(w)
else []
),
**config["scenario"],
run=config["run"]["name"],
),
lambda w: expand(
(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}_{planning_horizons}-heat_source_temperature_map_ambient_air.html"
if config_provider("plotting", "enable_heat_source_maps")(w)
and "air"
in config_provider("sector", "heat_pump_sources", "urban central")(w)
else []
),
**config["scenario"],
run=config["run"]["name"],
),
# Only river_water has energy maps
lambda w: expand(
(
RESULTS
+ "maps/static/base_s_{clusters}_{opts}_{sector_opts}_{planning_horizons}-heat_source_energy_map_river_water.html"
if config_provider("plotting", "enable_heat_source_maps")(w)
and "river_water"
in config_provider("sector", "heat_pump_sources", "urban central")(w)
else []
),
**config["scenario"],
run=config["run"]["name"],
),
expand(
RESULTS
+ "graphics/balance_timeseries/s_{clusters}_{opts}_{sector_opts}_{planning_horizons}",
run=config["run"]["name"],
**config["scenario"],
),
expand(
RESULTS
+ "graphics/heatmap_timeseries/s_{clusters}_{opts}_{sector_opts}_{planning_horizons}",
run=config["run"]["name"],
**config["scenario"],
expand(CORE_OUTPUTS, run=config["run"]["name"]),
(
expand(
NETWORK_PLOT_OUTPUTS,
run=config["run"]["name"],
horizon=config["planning_horizons"],
)
if NETWORK_PLOT_OUTPUTS
else []
),
expand(
RESULTS
+ "graphics/interactive_bus_balance/s_{clusters}_{opts}_{sector_opts}_{planning_horizons}",
run=config["run"]["name"],
**config["scenario"],
(
expand(
TIMESERIES_OUTPUTS,
run=config["run"]["name"],
horizon=config["planning_horizons"],
)
if TIMESERIES_OUTPUTS
else []
),
lambda w: balance_map_paths("static", w),
lambda w: balance_map_paths("interactive", w),
(expand(MYOPIC_OUTPUTS, run=config["run"]["name"]) if MYOPIC_OUTPUTS else []),
get_sector_network_plots,
get_balance_map_plots,
default_target: True


Expand Down
Loading