From d2b8537a4f10d616f0073fb13caa11067ff53151 Mon Sep 17 00:00:00 2001 From: Jan Tautorus Date: Wed, 12 Aug 2026 16:29:10 +0200 Subject: [PATCH] fix: make un_enerdata_demand_2050_final.csv an optional input data/un_enerdata_demand_2050_final.csv is a manually-provided, gitignored file that was unconditionally required by prepare_regional_network, calculate_regional_lcox, and model_trade, even though it's only actually read on the 'reserved' supply-curve scenario (local demand reservation target) and the unused 'hydrogen' final-product branch of model_trade.py. With the current default scenario (allocated_share) and final_product (steel), the file was dead weight that still had to exist on disk for the DAG to build. Make the input conditional on when it's actually consumed, so runs using allocated_share/unreserved or the steel chain no longer need it. --- rules/supply_curves.smk | 18 ++++++++++++++++-- rules/trade_model.smk | 8 +++++++- workflow/scripts/calculate_lcox.py | 7 +++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/rules/supply_curves.smk b/rules/supply_curves.smk index 194711e..dbe5ac9 100644 --- a/rules/supply_curves.smk +++ b/rules/supply_curves.smk @@ -12,6 +12,20 @@ def _process_label_for_product(product): return route_label_for_product(config, product) +def _local_demand_input(wildcards): + """Local electricity demand data, only when the 'reserved' scenario needs it. + + The 'reserved' scenario derives its capacity-reservation target from this + file unless reserve_local_demand_mw is set explicitly in config; the + 'unreserved' and 'allocated_share' scenarios never read it. + """ + needs_demand = ( + wildcards.scenario == "reserved" + and config.get("reserve_local_demand_mw", 0) <= 0 + ) + return "data/un_enerdata_demand_2050_final.csv" if needs_demand else [] + + def _product_uses_renewables(product): """Check if a product's stage group uses renewable_electricity. @@ -86,7 +100,7 @@ rule prepare_regional_network: ), renewables="resources/renewables_clustered.nc", tech_costs="resources/technology_data/costs_{cost_year}.csv", - local_demand="data/un_enerdata_demand_2050_final.csv", + local_demand=_local_demand_input, wacc="resources/wacc-clustered.csv", labour_cost="resources/labour_cost_clustered.csv", output: @@ -118,7 +132,7 @@ if config["enable"].get("run_supply_chain", True): rule calculate_regional_lcox: input: base_network="resources/networks/base_{cost_year}_{region}_{wacc}_{product}_{scenario}.nc", - local_demand="data/un_enerdata_demand_2050_final.csv", + local_demand=_local_demand_input, output: # Internal cache keyed by route_label for reuse; only products matter for supply curves results="resources/lco-{product}/cost_year~{cost_year}/wacc~{wacc}/{region}_{scenario}/results_{product_demand_mt}.csv", diff --git a/rules/trade_model.smk b/rules/trade_model.smk index 65516e8..018c092 100644 --- a/rules/trade_model.smk +++ b/rules/trade_model.smk @@ -23,7 +23,13 @@ rule model_trade: ), trade_options="resources/trade_opt_chokepoints.csv", bus_locations="data/bus_locations.csv", - demand="data/un_enerdata_demand_2050_final.csv", + # Only the hydrogen final product reads this file (model_trade.py); + # the active steel chain gets its demand from steel_demand instead. + demand=( + "data/un_enerdata_demand_2050_final.csv" + if config["trade_chains"]["final_product"] == "hydrogen" + else [] + ), steel_demand="resources/steel_demand_clustered_{cost_year}.csv", iron_ore="resources/ironore_production_clustered.csv", grid_potential="data/grid_potential_custom.csv", diff --git a/workflow/scripts/calculate_lcox.py b/workflow/scripts/calculate_lcox.py index 47f4eb2..3dda176 100644 --- a/workflow/scripts/calculate_lcox.py +++ b/workflow/scripts/calculate_lcox.py @@ -42,7 +42,14 @@ def load_demands_for_region(region, config): Returns dict with: - local_el_demand_mwh: MWh/year (for renewable constraint calculation) + + local_demand is only provided as an input for the 'reserved' scenario + (see _local_demand_input in rules/supply_curves.smk); other scenarios + don't use it and get 0 here. """ + if not snakemake.input.local_demand: + return {"local_el_demand_mwh": 0} + # Load local electricity demand (for renewable constraint calculation) try: local_df = pd.read_csv(snakemake.input.local_demand)