Cost-Benefit Analysis (CBA)¶
The Cost-Benefit Analysis (CBA) workflow is implemented in rules/cba.smk. Rules are organised into stages: Retrieve, Build MSV, Build rolling horizon, Postprocess and Benchmark. In addition, a Collect stage provides convenient target rules that run the workflow up to a specific stage, aggregating each stage's output across all configured wildcards.
Retrieve¶
Rule retrieve_tyndp_cba_projects¶
Downloads the CBA project explorer dataset, containing project definitions.
Rule retrieve_presolved_sb_networks¶
Downloads pre-solved SB networks from a previous Open-TYNDP release for use as CBA inputs
when cba.cba_scenario_input.use_presolved is true.
Build MSV¶
Rule clean_projects (checkpoint)¶
Extracts and cleans CBA transmission and storage projects from Excel exports.
Reads transmission projects from the "Trans.Projects" sheet of the CBA projects Excel file. For projects with multiple borders (newline-separated in the Excel), the script explodes these into separate rows, creating one row per border. Bus codes are extracted from the border strings (expected format: "BUS0-BUS1") and rows are filtered out with a warning when the format does not match, when either bus is absent from the TYNDP node list, or when no capacity is reported in either direction.
Reads storage projects from the "Stor.Projects" sheet. Each project's country is mapped
to a representative electricity bus. Storage projects are assigned TOOT or PINT based on
whether they are already part of the reference grid, same as transmission projects; TOOT
storage projects are not yet supported downstream (see prepare_project.py).
Custom PINT transmission projects can be configured using data/cba/custom_projects/transmission_projects.csv. With it,
the user can modify existing projects and add new ones. Transmission capacities are in MW.
-
Using an existing PINT combination (
project_id,bus0,bus1), the user can overwrite any field of an existing project with a custom value. Not all fields need to be specified; leaving a field empty keeps its existing value. -
New projects must use a new
project_idand are added as PINT links.
Inputs
data/tyndp_2024_bundle/cba_projects/20250312_export_transmission.xlsx: Excel file containing CBA transmission projectsdata/tyndp_2024_bundle/cba_projects/20250312_export_storage.xlsx: Excel file containing CBA storage projectsrules.retrieve_tyndp.output.nodes: TYNDP electricity node list used to validate bordersdata/cba/table_B1_CBA_Implementations_Guidelines_TYNDP2024.csv: Table of projects as defined in the Implementation Guidelines Appendix B.1, used to assign the TOOT/PINT method per project and planning horizondata/cba/cba_project_corrections.csv: Manually curated bus0/bus1/p_nom corrections for CBA projects, applied in place of the corresponding raw Excel entriesdata/cba/custom_projects/transmission_projects.csv: File used to configure custom transmission projects. With it, the user can modify existing projects and add new ones.data/cba/custom_projects/generators_static.csv: File used to configure custom generators. With it, user can modify static attributes of existing or new generators attached to a transmission / storage project.data/cba/custom_projects/generators_dynamic.csv: File used to configure custom generators. With it, user can modify dynamic attributes of existing or new generators attached to a transmission / storage project.
Outputs
resources/cba/transmission_projects.csv: Cleaned CSV with columns:project_id: Integer project identifierproject_name: Project nameis_crossborder: Whether the project is reported as cross-borderborder: Border string in format "BUS0-BUS1"p_nom 0->1: Transfer capacity increase from bus0 to bus1 (MW)p_nom 1->0: Transfer capacity increase from bus1 to bus0 (MW)bus0: Source bus code (4 alphanumeric characters)bus1: Destination bus code (4 alphanumeric characters)length_km: Total route length in km (from Trans.Investments)capex_meur: Total estimated CAPEX in MEUR (from Trans.Investments)-
underwater_fraction: Fraction of route that is offshore cable -
resources/cba/storage_projects.csv: Cleaned CSV with columns: project_id: Integer project identifierproject_name: Project namecapex_meur: Estimated total CAPEX in MEURopex_meur_per_year: Estimated annual OPEX in MEUR/yearp_nom_discharge: Total turbining/discharge capacity (MW)e_nom_gwh: Storage capacity (GWh)p_nom_charge: Total pumping/charge capacity (MW)roundtrip_efficiency: Roundtrip efficiency (fraction)lifetime_years: Operational lifetime (years); missing or zero values are replaced withcba.storage.default_lifetimecarrier: PyPSA carrier name for the storage technology-
bus: Representative electricity bus for the project's country -
resources/cba/cba_project_methods.csv: Table defining the assignment method of each project. -
resources/cba/generator_projects_static.csv: Cleaned CSV of custom generators, one row per generator, with columns: project_name: Name of the project the generator is grouped withproject_type: Type of that project,tfor transmission orsfor storageproject_id: Integer identifier of that projectgenerator_name: Generator name, unique within a projectcarrier: PyPSA carrier name of the generatorbus: Electricity bus the generator is attached top_nom: Nominal capacity (MW)marginal_cost: Marginal cost (EUR/MWh); missing values are replaced with 0capital_cost: Capital cost (EUR/MW); missing values are replaced with 0-
efficiency: Conversion efficiency (fraction); missing values are replaced with 1 -
resources/cba/generator_projects_dynamic.csv: Time-varying attributes of the same generators, in wide format with a two-row header and the snapshots as index: - Row 1:
mapping_idof the generator the column belongs to having the format<project_type><project_id>_<generator_name> - Row 2: PyPSA
Generatorinput timeseries attribute the column provides (e.g.p_max_pu,p_min_pu,efficiency,marginal_cost,p_set)
Rule clean_tyndp_indicators¶
Extract and clean 2024 TYNDP CBA indicators for transmission and storage projects.
Reads scenario sheets (tabs starting with 2030/2040), maps shortcuts using the table on the "Readme" tab, and outputs a long-format CSV.
Rule simplify_sb_network¶
Simplify scenario building network for CBA analysis.
Creates the base CBA network with: - Fixed optimal capacities from scenario building - Hurdle costs on DC links - Extended primary fuel source capacities - Merge low and high voltage buses - Convert bidirectional DC links to unidirectional links
Inputs
- Solved network from scenario building workflow
Outputs
resources/cba/networks/simple_{planning_horizons}.nc: Simplified network for CBA
Rule fix_reference_sb_to_cba¶
Build a Link dataframe of capacity corrections to align SB transmission projects with the CBA reference grid. A positive p_nom indicates capacity to add (potentially as a new link), while a negative p_nom indicates capacity to reduce on an existing link.
This only works for 2040, as we are assuming the 2030 reference grid does not need corrections.
Rule prepare_reference¶
Prepare CBA reference network with all TOOT projects included.
Takes the simplified network and ensures all projects that will be evaluated with TOOT methodology are present. This creates a common baseline for both MSV extraction and TOOT/PINT evaluation.
TODO: Implement project addition logic - currently passes through unchanged.
Rule build_msv_snapshot_weightings¶
Generate snapshot weightings for MSV extraction temporal aggregation.
Produces a CSV with resampled snapshot weightings at the configured
MSV extraction resolution. Follows the same logic as time_aggregation.py
for the supported resolution formats:
false: No aggregation, outputs empty CSV"Nsn": Representative snapshots (e.g., "2sn"), outputs empty CSV (handled directly byset_temporal_aggregation)"Nh": Hourly resampling (e.g., "24H", "48H"), outputs resampled weightings
Inputs
resources/cba/networks/reference_{planning_horizons}.nc: Reference network
Outputs
resources/cba/msv_snapshot_weightings_{planning_horizons}.csv: Snapshot weightings
Build rolling horizon¶
Rule prepare_rolling_horizon¶
Prepare network for cost-benefit analysis rolling horizon dispatch.
Modifications applied: - cyclic_carriers: keep cyclicity (short-term, e.g., batteries) - All other stores/storage units: disable cyclicity, apply marginal storage value, and set initial state of charge from perfect foresight for those that were cyclic in the full-year optimisation - Remove global constraints not needed for cost-benefit analysis - Disable volume limits (e_sum_min/e_sum_max)
Rule prepare_project¶
Prepare a single CBA project network based on the assigned method (TOOT/PINT).
TOOT removes the project from the reference network, PINT adds the project. Handles multi-border projects, creates links when needed, and validates capacity changes.
Solve¶
Rule solve_cba_msv_extraction¶
Extract marginal storage values via perfect foresight optimization.
Solves the reference network with perfect foresight (full year) to extract shadow prices from store energy balance constraints. These values capture the future value of stored energy and guide seasonal storage dispatch in rolling horizon optimization.
Inputs
resources/cba/networks/reference_{planning_horizons}.nc: Reference networkresources/cba/msv_snapshot_weightings_{planning_horizons}.csv: Snapshot weightings (optional)
Outputs
resources/cba/networks/msv_{planning_horizons}.nc: Network with marginal storage values in stores_t.mu_energy_balance
Rule solve_cba_reference_network¶
Solves the reference network using the rolling horizon approach. Shares the script with
solve_cba_network.
Solves optimal operation in rolling horizons for fixed capacities.
This script is used for optimizing the electrical network as well as the sector coupled network.
Description
The optimization is based on the network.optimize_with_rolling_horizon method.
Additionally, some extra constraints specified in solve_network are added, if
they apply to the dispatch.
Rule solve_cba_network¶
Solves the CBA network using the rolling horizon approach. Shares the script with solve_cba_reference_network.
Solves optimal operation in rolling horizons for fixed capacities.
This script is used for optimizing the electrical network as well as the sector coupled network.
Description
The optimization is based on the network.optimize_with_rolling_horizon method.
Additionally, some extra constraints specified in solve_network are added, if
they apply to the dispatch.
Postprocess¶
Rule make_indicators¶
Calculate CBA indicators by comparing reference and project scenarios.
This script computes the B1 indicator (operational cost difference) and other CBA metrics by analyzing the solved networks for reference and project cases.
PINT (Put In at a Time):
- Reference: Network WITHOUT any projects
- Project: Network WITH the specific project added
- B1 = OPEX(reference) - OPEX(with project)
TOOT (Take Out One at a Time):
- Reference: Network WITH all projects (current plan)
- Project: Network WITHOUT the specific project (removed)
- B1 = OPEX(without project) - OPEX(reference)
References:
- CBA guidelines, section 3.2.2: TOOT and PINT, page 23-24
- CBA implementation guidelines, section 5.1: B1 - SEW, page 58-59
Rule combine_indicators¶
Concatenate indicators from individual indicators files.
This script reads all individual project indicator CSV files and combines them into a single CSV file.
Rule plot_indicators¶
Create plots for CBA indicators.
This script reads the combined indicators CSV file and generates various plots to visualize the cost-benefit analysis results, including the B1 indicator (Total System Cost difference).
Benchmark¶
Rule plot_cba_benchmark¶
Plots per-project indicator benchmarking charts comparing computed indicators against
TYNDP 2024 reference values. Shares the script with plot_weather_benchmark.
Create benchmark plots for CBA indicators.
This script reads a indicators CSV file that includes Open-TYNDP rows and TYNDP benchmark rows, and generates plots comparing Open-TYNDP values to the 2024 TYNDP values.
Rule plot_weather_benchmark¶
Plots weather ensemble benchmarking charts from indicators aggregated across climate years.
Shares the script with plot_cba_benchmark.
Create benchmark plots for CBA indicators.
This script reads a indicators CSV file that includes Open-TYNDP rows and TYNDP benchmark rows, and generates plots comparing Open-TYNDP values to the 2024 TYNDP values.
Rule average_indicators_per_project_and_planning_horizon¶
Collect indicators from individual indicators files and create weighted average indicator.
This script reads all collected project indicators from the different weather years and calculates a new combined indicator which is stores in a new CSV file.
Rule summarize_indicators_per_project¶
Collect indicators from individual indicators files and create weighted average indicator.
This script reads all collected project indicators from the different weather years and calculates a new combined indicator which is stores in a new CSV file.
Rule summarize_all_indicators¶
Collect indicators from individual indicators files and create weighted average indicator.
This script reads all collected project indicators from the different weather years and calculates a new combined indicator which is stores in a new CSV file.
Collect¶
Aggregate rules that run the corresponding base rule across all configured wildcards. They do not have dedicated scripts.
Rule prepare_references¶
Aggregate prepare_reference outputs.
Rule collect_cba_data¶
Collects the data the CBA needs before the clean_projects
checkpoint expands the graph: the project data the checkpoint reads, and the pre-solved SB networks
where cba: cba_scenario_input: use_presolved: true. Running the rule also runs the checkpoint.
Used by pixi run collect-data-cba, see
Filling the cache with network access.
Rule cba¶
Top-level target rule. Collects ensemble outputs from all climate year runs in a collection
scenario (e.g. NT-cyears) and the per-scenario results from nested runs.