From 67afe1893223509f2c5289658606a8f4d757ef29 Mon Sep 17 00:00:00 2001 From: florianh Date: Sun, 28 Jun 2026 14:28:48 +0200 Subject: [PATCH 1/8] cap_apr26_reg: continuous parametric regional cap + AR6 GWP; MACC fade-in; soil-C carry-forward MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cap_apr26_reg (module 56 GHG-policy realization): - Continuous parametric regional cap: a config-driven, time-flexible cap trajectory (s56_emis_cap_parametric switch + start/target year and start/endpoint value scalars in input.gms; m_linear_time_interpol in preloop.gms). The cap is free before s56_emis_cap_start_year, ramps linearly from s56_emis_cap_start_value to s56_emis_cap_target by s56_emis_cap_target_year, and is held at the target for all later years (works for any horizon, incl. runs to 2100). No cs3 columns / capscen56 set entries needed. It is applied to the region(s) selected via policy_countries56 (config-driven region mask p56_cap_region, no hard-coded region — mirrors the existing country->region price-share machinery). With s56_emis_cap_parametric=0 (default) the cs3 path is used unchanged. - GWP basis switched AR5 -> AR6 (CH4 28->27, N2O 265->273) so the capped quantity uses the same GWP100 basis as the magpie4 GWP100AR6|Land reporting. 57_maccs/on_aug22: - Optional linear fade-in of the prescribed s57_maxmac steps (s57_maxmac_fadein/_start/_end). Gated: fadein=0 reproduces the flat baseline. 59_som (cellpool_jan23, static_jan19): - Carry the soil-C stock forward to the next timestep (as done for the above-ground pools), fixing soil-C telescoping under the cap (= PR #904). config/default.cfg: - Defaults for the new switches: the parametric cap (s56_emis_cap_parametric + start_year/start_value/target_year/target) and the MACC fade-in (s57_maxmac_fadein/_start/_end). scripts/start: NZB run setups using the parametric cap / no-cap reference runs (parametric +-200 extension, lever corners, baseline variants, reference runs). Parametric runs select the capped region via policy_countries56 (e.g. "BRA"). --- config/default.cfg | 13 +++ .../cap_apr26_reg/declarations.gms | 2 + modules/56_ghg_policy/cap_apr26_reg/input.gms | 14 +++ .../56_ghg_policy/cap_apr26_reg/preloop.gms | 29 +++++-- modules/57_maccs/on_aug22/declarations.gms | 1 + modules/57_maccs/on_aug22/input.gms | 3 + modules/57_maccs/on_aug22/preloop.gms | 22 +++-- modules/59_som/cellpool_jan23/postsolve.gms | 3 + modules/59_som/static_jan19/postsolve.gms | 3 + scripts/start/nzb_R0_npi_cpriceAR.R | 68 +++++++++++++++ scripts/start/nzb_R0_npi_fullmacc_rest.R | 54 ++++++++++++ scripts/start/nzb_R0_ref.R | 87 +++++++++++++++++++ scripts/start/nzb_baseline_variants.R | 74 ++++++++++++++++ scripts/start/nzb_cap_extend_onon.R | 70 +++++++++++++++ scripts/start/nzb_nocap_corners.R | 63 ++++++++++++++ 15 files changed, 496 insertions(+), 10 deletions(-) create mode 100644 scripts/start/nzb_R0_npi_cpriceAR.R create mode 100644 scripts/start/nzb_R0_npi_fullmacc_rest.R create mode 100644 scripts/start/nzb_R0_ref.R create mode 100644 scripts/start/nzb_baseline_variants.R create mode 100644 scripts/start/nzb_cap_extend_onon.R create mode 100644 scripts/start/nzb_nocap_corners.R diff --git a/config/default.cfg b/config/default.cfg index f3a0b48be2..a0a01d5a29 100644 --- a/config/default.cfg +++ b/config/default.cfg @@ -1616,6 +1616,14 @@ cfg$gms$s56_emis_cap_start <- 2025 cfg$gms$s56_emis_cap_penalty <- 1e5 cfg$gms$c56_cap_policy <- "reddnatveg_nosoil" cfg$gms$s56_source_bounds_on <- 0 +# continuous parametric regional cap (overrides the cs3 path when =1; applied to +# the regions selected via policy_countries56). Free before start_year, linear +# ramp start_value -> target by target_year, held at target afterwards. +cfg$gms$s56_emis_cap_parametric <- 0 # def = 0 (cs3 path used) +cfg$gms$s56_emis_cap_start_year <- 2035 # def = 2035 +cfg$gms$s56_emis_cap_start_value <- 600 # def = 600 +cfg$gms$s56_emis_cap_target_year <- 2050 # def = 2050 +cfg$gms$s56_emis_cap_target <- 0 # def = 0 # * Switch for scaling GHG price with development state (1=on 0=off) cfg$gms$s56_ghgprice_devstate_scaling <- 0 # def = 0 @@ -1847,6 +1855,11 @@ cfg$gms$s57_maxmac_n_awms <- -1 # def = -1 cfg$gms$s57_maxmac_ch4_rice <- -1 # def = -1 cfg$gms$s57_maxmac_ch4_entferm <- -1 # def = -1 cfg$gms$s57_maxmac_ch4_awms <- -1 # def = -1 +# optional linear fade-in of the prescribed s57_maxmac steps over time +# (fadein=0 reproduces the flat baseline; only relevant when s57_maxmac_* >= 0) +cfg$gms$s57_maxmac_fadein <- 0 # def = 0 +cfg$gms$s57_maxmac_fadein_start <- 2025 # def = 2025 +cfg$gms$s57_maxmac_fadein_end <- 2050 # def = 2050 # ***--------------------- 58_peatland ------------------------------------ # * (off): Peatland area and associated GHG emissions are assumed zero diff --git a/modules/56_ghg_policy/cap_apr26_reg/declarations.gms b/modules/56_ghg_policy/cap_apr26_reg/declarations.gms index 0ec161832b..5b50d1dbbc 100644 --- a/modules/56_ghg_policy/cap_apr26_reg/declarations.gms +++ b/modules/56_ghg_policy/cap_apr26_reg/declarations.gms @@ -24,6 +24,8 @@ parameters p56_gwp(pollutants) AR5 GWP factors for CO2eq conversion (Tg CO2eq per Tg native unit) p56_cap_mask(emis_source,pollutants) Policy mask for cap scope: 1=included 0=excluded (1) p56_emis_cap(t_all,i) Active regional AFOLU cap per region (Tg CO2eq per yr) + p56_cap_region(i) Regions the parametric cap applies to (1=capped derived from policy_countries56) (1) + p56_emis_cap_param(t_all) Parametric cap trajectory over time (Tg CO2eq per yr) p56_emis_cap_slack(t,i) Regional slack level — platform infeasibility signal (Tg CO2eq per yr) * ov56_emis_co2eq declared here (not in R section) because it is computed manually * in postsolve rather than copied from a GAMS variable attribute (.l/.m/.up/.lo). diff --git a/modules/56_ghg_policy/cap_apr26_reg/input.gms b/modules/56_ghg_policy/cap_apr26_reg/input.gms index fa5d6eeb0e..62510cea0d 100644 --- a/modules/56_ghg_policy/cap_apr26_reg/input.gms +++ b/modules/56_ghg_policy/cap_apr26_reg/input.gms @@ -83,6 +83,20 @@ scalars s56_emis_cap_start First year the emissions cap is binding (yr) / 2025 / s56_emis_cap_penalty Penalty cost for slack (mio USD17MER per Tg CO2eq per yr) / 1e+05 / s56_source_bounds_on Switch for Archetype A source-specific bounds (1=on 0=off) / 0 / +* ---- cap_apr26_reg: continuous parametric regional cap (overrides cs3 when on) ---- +*' Builds an arbitrary regional AFOLU cap trajectory from config scalars, flexible +*' in time (no cs3 columns / capscen56 entries needed). The cap is free (1e6) +*' before s56_emis_cap_start_year, ramps linearly from s56_emis_cap_start_value at +*' that year to s56_emis_cap_target at s56_emis_cap_target_year, and is held at the +*' target for all later years (so runs to 2100 are covered). It is applied to the +*' region(s) selected via policy_countries56 (config-driven, no hard-coded region; +*' set it to the target region's ISO codes). With s56_emis_cap_parametric=0 +*' (default) the cs3 path is used unchanged. + s56_emis_cap_parametric Switch for continuous parametric regional cap (1=on overrides cs3 0=off) / 0 / + s56_emis_cap_start_year Year the parametric cap starts ramping - free before (yr) / 2035 / + s56_emis_cap_start_value Parametric cap level at the start year (Tg CO2eq per yr) / 600 / + s56_emis_cap_target_year Year the parametric cap endpoint is reached and held (yr) / 2050 / + s56_emis_cap_target Parametric AFOLU cap endpoint for the selected region(s) (Tg CO2eq per yr) / 0 / ; $setglobal c56_pollutant_prices none diff --git a/modules/56_ghg_policy/cap_apr26_reg/preloop.gms b/modules/56_ghg_policy/cap_apr26_reg/preloop.gms index 20a97e88d5..3f704714eb 100644 --- a/modules/56_ghg_policy/cap_apr26_reg/preloop.gms +++ b/modules/56_ghg_policy/cap_apr26_reg/preloop.gms @@ -122,14 +122,17 @@ p56_c_price_aff(t_all,i,ac)$(ac.off >= s56_c_price_exp_aff/5) = sum(ac_exp, p56_ *zero C price before starting year p56_c_price_aff(t_all,i,ac)$(m_year(t_all) <= max(m_year("%c56_mute_ghgprices_until%"),s56_fader_start*s56_ghgprice_fader)) = 0; -* ---- cap_apr26_reg: GWP factors (AR5, 100-yr) ---- -*' CH4=28, N2O=265. co2_c is in Tg C so multiply by 44/12 for Tg CO2. +* ---- cap_apr26_reg: GWP factors (AR6, 100-yr) ---- +*' AR6 GWP100 (IPCC AR6 WG1 Ch7): CH4(non-fossil)=27, N2O=273. Matches the +*' magpie4 GWP100AR6 reporting convention (reportEmissions.R: ch4*27, n2o*273) +*' so the cap quantity uses the SAME GWP basis as the reported GWP100AR6|Land. +*' co2_c is in Tg C so multiply by 44/12 for Tg CO2. *' Non-GHG nitrogen forms (nh3_n, no2_n, no3_n) are zero. p56_gwp(pollutants) = 0; p56_gwp("co2_c") = 44/12; -p56_gwp("ch4") = 28; -p56_gwp("n2o_n_direct") = 265 * 44/28; -p56_gwp("n2o_n_indirect") = 265 * 44/28; +p56_gwp("ch4") = 27; +p56_gwp("n2o_n_direct") = 273 * 44/28; +p56_gwp("n2o_n_indirect") = 273 * 44/28; * ---- cap_apr26_reg: cap policy scope mask ---- *' Sources with mask=0 contribute zero CO2eq to q56_emis_cap(i). @@ -143,6 +146,22 @@ p56_emis_cap(t_all,i) = 1e6; $ifthen not "%c56_emis_cap_scenario%" == "none" p56_emis_cap(t_all,i) = f56_emis_cap(t_all,i,"%c56_emis_cap_scenario%"); $endif + +*' Continuous parametric regional cap (optional). When s56_emis_cap_parametric=1 +*' the cs3-selected trajectory above is replaced by a time-flexible ramp: free +*' (1e6) before s56_emis_cap_start_year, then a linear interpolation from +*' s56_emis_cap_start_value (at the start year) to s56_emis_cap_target (at +*' s56_emis_cap_target_year), held at the target for all later years (so runs to +*' 2100 are covered). It is applied only to regions FULLY composed of +*' policy_countries56 (a hard cap on a partial region is not meaningful); set +*' policy_countries56 to the target region's ISO codes. All other regions stay free. +p56_cap_region(i) = 1$(sum(i_to_iso(i,iso), 1 - p56_country_switch(iso)) = 0); +if(s56_emis_cap_parametric = 1, + m_linear_time_interpol(p56_emis_cap_param,s56_emis_cap_start_year,s56_emis_cap_target_year,s56_emis_cap_start_value,s56_emis_cap_target); + p56_emis_cap(t_all,i) = 1e6; + p56_emis_cap(t_all,i)$(p56_cap_region(i) AND m_year(t_all) >= s56_emis_cap_start_year) = p56_emis_cap_param(t_all); +); + p56_emis_cap(t_all,i)$(m_year(t_all) <= sm_fix_SSP2) = 1e6; p56_emis_cap(t_all,i)$(m_year(t_all) > sm_fix_SSP2 AND m_year(t_all) < s56_emis_cap_start) = 1e6; diff --git a/modules/57_maccs/on_aug22/declarations.gms b/modules/57_maccs/on_aug22/declarations.gms index 6abdd88c98..3493197be3 100644 --- a/modules/57_maccs/on_aug22/declarations.gms +++ b/modules/57_maccs/on_aug22/declarations.gms @@ -7,6 +7,7 @@ scalars s57_step_length Step length in MACC data (USD17MER) + s57_fade Helper for the linear phase-in of the prescribed maxmac steps (1) ; parameters diff --git a/modules/57_maccs/on_aug22/input.gms b/modules/57_maccs/on_aug22/input.gms index 19132524a2..97146cd41a 100644 --- a/modules/57_maccs/on_aug22/input.gms +++ b/modules/57_maccs/on_aug22/input.gms @@ -16,6 +16,9 @@ scalars s57_maxmac_ch4_rice activate rice CH4 mitigation independent of pollutant price (step of MACC and -1 is inactive)/ -1 / s57_maxmac_ch4_entferm activate enteric fermentation CH4 mitigation independent of pollutant price (step of MACC and -1 is inactive) / -1 / s57_maxmac_ch4_awms activate awms CH4 mitigation independent of pollutant price (step of MACC and -1 is inactive) / -1 / + s57_maxmac_fadein switch to phase-in the prescribed s57_maxmac steps linearly over time (1) instead of applying them flat (0) / 0 / + s57_maxmac_fadein_start first year of the linear maxmac phase-in - the step equals 1 at and before this year / 2025 / + s57_maxmac_fadein_end year at which the linear maxmac phase-in reaches the full prescribed s57_maxmac step (held constant afterwards) / 2050 / s57_implicit_emis_factor emission factor for direct soil emissions implicit to MACC curves (tN2ON per tN) / 0.01 / s57_implicit_fert_cost fertilizer costs implicit to MACC curves (USD17MER per ton N) / 738 / ; diff --git a/modules/57_maccs/on_aug22/preloop.gms b/modules/57_maccs/on_aug22/preloop.gms index 294223064c..db7d8783ac 100644 --- a/modules/57_maccs/on_aug22/preloop.gms +++ b/modules/57_maccs/on_aug22/preloop.gms @@ -25,15 +25,27 @@ i57_mac_step_n2o(t,i,emis_source) = min(201, ceil(im_pollutant_prices(t,i,"n2o_n i57_mac_step_ch4(t,i,emis_source) = min(201, ceil(im_pollutant_prices(t,i,"ch4",emis_source)/25*44/12 / s57_step_length) + 1); +*** The s57_maxmac_* scalars prescribe a non-CO2 mitigation level (MACC step 1..201) +*** independent of the pollutant price. By default (s57_maxmac_fadein = 0) they are applied +*** flat from sm_fix_SSP2 onwards. With s57_maxmac_fadein = 1 the prescribed step is phased +*** in linearly from step 1 at s57_maxmac_fadein_start to the full s57_maxmac_* step at +*** s57_maxmac_fadein_end, and held constant afterwards. With fadein = 0 the factor s57_fade +*** equals 1 in every applicable timestep, so the original flat behaviour is reproduced +*** bit-for-bit. loop(t, if(m_year(t) > sm_fix_SSP2, - if (s57_maxmac_n_soil >= 0, i57_mac_step_n2o(t,i,emis_source_inorg_fert_n2o) = s57_maxmac_n_soil); - if (s57_maxmac_n_awms >= 0, i57_mac_step_n2o(t,i,emis_source_awms_n2o) = s57_maxmac_n_awms); - if (s57_maxmac_ch4_rice >= 0, i57_mac_step_ch4(t,i,emis_source_rice_ch4) = s57_maxmac_ch4_rice); - if (s57_maxmac_ch4_entferm >= 0, i57_mac_step_ch4(t,i,emis_source_ent_ferm_ch4) = s57_maxmac_ch4_entferm); - if (s57_maxmac_ch4_awms >= 0, i57_mac_step_ch4(t,i,emis_source_awms_ch4) = s57_maxmac_ch4_awms); + s57_fade = 1; + if ((s57_maxmac_fadein = 1) and (s57_maxmac_fadein_end > s57_maxmac_fadein_start), + s57_fade = min(1, max(0, (m_year(t) - s57_maxmac_fadein_start) / (s57_maxmac_fadein_end - s57_maxmac_fadein_start))); + ); + + if (s57_maxmac_n_soil >= 0, i57_mac_step_n2o(t,i,emis_source_inorg_fert_n2o) = round(1 + (s57_maxmac_n_soil - 1) * s57_fade)); + if (s57_maxmac_n_awms >= 0, i57_mac_step_n2o(t,i,emis_source_awms_n2o) = round(1 + (s57_maxmac_n_awms - 1) * s57_fade)); + if (s57_maxmac_ch4_rice >= 0, i57_mac_step_ch4(t,i,emis_source_rice_ch4) = round(1 + (s57_maxmac_ch4_rice - 1) * s57_fade)); + if (s57_maxmac_ch4_entferm >= 0, i57_mac_step_ch4(t,i,emis_source_ent_ferm_ch4) = round(1 + (s57_maxmac_ch4_entferm - 1) * s57_fade)); + if (s57_maxmac_ch4_awms >= 0, i57_mac_step_ch4(t,i,emis_source_awms_ch4) = round(1 + (s57_maxmac_ch4_awms - 1) * s57_fade)); ); ); diff --git a/modules/59_som/cellpool_jan23/postsolve.gms b/modules/59_som/cellpool_jan23/postsolve.gms index ea42e490a4..14b6f7841f 100644 --- a/modules/59_som/cellpool_jan23/postsolve.gms +++ b/modules/59_som/cellpool_jan23/postsolve.gms @@ -9,6 +9,9 @@ pc59_som_pool(j,land) = v59_som_pool.l(j,land); pc59_land_before(j,land) = vm_land.l(j,land); pc59_carbon_density(j,land)$(pc59_land_before(j,land) > 1e-10) = pc59_som_pool(j,land) / pc59_land_before(j,land); +*** Carry the soil carbon stock forward to the next timestep (as done for the above-ground pools in 56_ghg_policy). +pcm_carbon_stock(j,land,"soilc",stockType) = vm_carbon_stock.l(j,land,"soilc",stockType); + *#################### R SECTION START (OUTPUT DEFINITIONS) ##################### ov59_som_target(t,j,land,"marginal") = v59_som_target.m(j,land); ov59_som_pool(t,j,land,"marginal") = v59_som_pool.m(j,land); diff --git a/modules/59_som/static_jan19/postsolve.gms b/modules/59_som/static_jan19/postsolve.gms index 32fda876c4..d4e986befc 100644 --- a/modules/59_som/static_jan19/postsolve.gms +++ b/modules/59_som/static_jan19/postsolve.gms @@ -7,6 +7,9 @@ +*** Carry the soil carbon stock forward to the next timestep (as done for the above-ground pools in 56_ghg_policy). +pcm_carbon_stock(j,land,"soilc",stockType) = vm_carbon_stock.l(j,land,"soilc",stockType); + *#################### R SECTION START (OUTPUT DEFINITIONS) ##################### ov_nr_som(t,j,"marginal") = vm_nr_som.m(j); ov_nr_som_fertilizer(t,j,"marginal") = vm_nr_som_fertilizer.m(j); diff --git a/scripts/start/nzb_R0_npi_cpriceAR.R b/scripts/start/nzb_R0_npi_cpriceAR.R new file mode 100644 index 0000000000..59c2ab6d56 --- /dev/null +++ b/scripts/start/nzb_R0_npi_cpriceAR.R @@ -0,0 +1,68 @@ +## nzb_R0_npi_cpriceAR.R -------------------------------------------------------- +## New no-cap reference: NPI forest + a 1.5C CO2 PRICE (BRA) that drives BOTH the +## non-CO2 MACCs AND carbon-price-induced afforestation/reforestation (A/R), with +## Half-Earth restoration OFF. Purpose: test whether price-driven A/R can deliver +## a deeper BRA land-CO2 sink by 2050 than the forced Half-Earth restoration. +## +## Mechanism (verified in cap_apr26_reg + module 57): +## - c56_pollutant_prices = R34M410-SSP2-PkBudg650 -> 1.5C price (~641 USD/tCO2eq +## by 2050; the same level as MACC step 106). Applied to BRA only via +## policy_countries56="BRA"; rest of world stays at NPi2025 (noselect). Price is +## muted until 2030 (c56_mute_ghgprices_until) then follows the PkBudg650 path. +## - s57_maxmac_* = -1 -> MACC abatement is PRICE-DRIVEN (forced override off). +## - s56_c_price_induced_aff = 1 -> the CO2 price rewards A/R (faded in from 2030). +## - restoration off: c22_protect_scenario=none, s22_restore_land=0 (WDPA base only). +## - no cap, nocc, NPI forest policy. +## --------------------------------------------------------------------------- +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +cfg$gms$ghg_policy <- "cap_apr26_reg" +cfg$gms$c56_cap_policy <- "all" +cfg$gms$c56_emis_cap_scenario <- "none" # NO cap +cfg$gms$s56_emis_cap_parametric <- 0 +cfg$gms$s56_source_bounds_on <- 0 + +# --- 1.5C CO2 price for BRA (drives MACC + A/R); rest of world at NPi baseline --- +cfg$gms$c56_pollutant_prices <- "R34M410-SSP2-PkBudg650" +cfg$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" +cfg$gms$policy_countries56 <- "BRA" +# carbon-price-induced afforestation ON (faded in from 2030) +cfg$gms$s56_c_price_induced_aff <- 1 + +# --- price-driven MACC (forced override OFF) --- +cfg$gms$s57_maxmac_n_soil <- -1 +cfg$gms$s57_maxmac_n_awms <- -1 +cfg$gms$s57_maxmac_ch4_rice <- -1 +cfg$gms$s57_maxmac_ch4_entferm <- -1 +cfg$gms$s57_maxmac_ch4_awms <- -1 +cfg$gms$s57_maxmac_fadein <- 0 + +# --- NPI forest policy --- +cfg$gms$c32_aff_policy <- "npi" +cfg$gms$c35_ad_policy <- "npi" +cfg$gms$c35_aolc_policy <- "npi" + +# --- restoration OFF (WDPA base protection only) --- +cfg$gms$c22_protect_scenario <- "none" +cfg$gms$c22_protect_scenario_noselect <- "none" +cfg$gms$policy_countries22 <- "BRA" +cfg$gms$s22_restore_land <- 0 + +cfg$gms$c_timesteps <- "5year2050" +cfg$output <- c("rds_report") +cfg$sequential <- FALSE + +cfg$title <- "nzb_R0_npi_cpriceAR" +start_run(cfg, codeCheck = FALSE) diff --git a/scripts/start/nzb_R0_npi_fullmacc_rest.R b/scripts/start/nzb_R0_npi_fullmacc_rest.R new file mode 100644 index 0000000000..c993ed2b74 --- /dev/null +++ b/scripts/start/nzb_R0_npi_fullmacc_rest.R @@ -0,0 +1,54 @@ +## nzb_R0_npi_fullmacc_rest.R --------------------------------------------------- +## Corrected baseline variant: NPI forest policy + FULL MACC potential (step 201) +## + restoration ON (Half-Earth PBL, BRA). No cap. (Replaces the mistaken +## nzb_R0_npi_fullmacc which had restore OFF.) +## Same baseline frame as the other variants: nocc, non-binding cap, no GHG prices. +## --------------------------------------------------------------------------- +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +cfg$gms$ghg_policy <- "cap_apr26_reg" +cfg$gms$c56_cap_policy <- "all" +cfg$gms$c56_emis_cap_scenario <- "none" # non-binding (no cap) +cfg$gms$s56_emis_cap_parametric <- 0 +cfg$gms$s56_source_bounds_on <- 0 +cfg$gms$c56_pollutant_prices <- "none" +cfg$gms$s56_c_price_induced_aff <- 0 +cfg$gms$c_timesteps <- "5year2050" +cfg$output <- c("rds_report") +cfg$sequential <- FALSE + +# forest policy = NPI (default, set explicitly) +cfg$gms$c32_aff_policy <- "npi" +cfg$gms$c35_ad_policy <- "npi" +cfg$gms$c35_aolc_policy <- "npi" + +# restoration ON (Half-Earth PBL, BRA) +cfg$gms$c22_protect_scenario <- "PBL_HalfEarth" +cfg$gms$c22_protect_scenario_noselect <- "none" +cfg$gms$policy_countries22 <- "BRA" +cfg$gms$s22_restore_land <- 1 + +# FULL MACC potential: max curve step 201 (~1222 USD/tCO2eq), phased in as usual +cfg$gms$s57_maxmac_n_soil <- 201 +cfg$gms$s57_maxmac_n_awms <- 201 +cfg$gms$s57_maxmac_ch4_rice <- 201 +cfg$gms$s57_maxmac_ch4_entferm <- 201 +cfg$gms$s57_maxmac_ch4_awms <- 201 +cfg$gms$s57_maxmac_fadein <- 1 +cfg$gms$s57_maxmac_fadein_start <- 2025 +cfg$gms$s57_maxmac_fadein_end <- 2050 + +cfg$title <- "nzb_R0_npi_fullmacc_rest" +start_run(cfg, codeCheck = FALSE) diff --git a/scripts/start/nzb_R0_ref.R b/scripts/start/nzb_R0_ref.R new file mode 100644 index 0000000000..23e5bc76b6 --- /dev/null +++ b/scripts/start/nzb_R0_ref.R @@ -0,0 +1,87 @@ +## nzb_R0_ref.R -------------------------------------------------------------- +## NZB R0 REFERENCE run (no binding cap). Locates where Brazil's reported AFOLU +## lands from the prescribed levers ALONE, before any cap binds. +## +## Revised design (call with Alex Koberle, 2026-06-25; recipe (a)): +## - NO climate-change impacts -> setScenario(cfg, "nocc") sets all 7 climate +## switches (c14 yields, c35 pot_forest, c42/c43 water, c52 carbon, +## c52 land_carbon_sink, c59 som). Pure bookkeeping convention. +## - NO GHG prices -> c56_pollutant_prices = "none" (im_pollutant_prices = 0), +## s56_c_price_induced_aff = 0. Reason: do not distort the deforestation signal. +## - A/R via restoration -> Half-Earth PBL conservation, BRA only, forced, +## phased 2025->2050 (the knob that will later vary with the cap). +## - Non-CO2 via FIXED 1.5C MACC fade -> s57_maxmac_* = 106 (= PkBudg650 2050 +## step: co2_c 2350 USD/tC ~ 641 USD/tCO2eq; step = ceil(2350/22.4)+1 = 106), +## phased linearly from step 1 @2025 to 106 @2050 (s57_maxmac_fadein = 1). +## All five non-CO2 sources. Global (BRA-only MACC is a later refinement). +## - Cap scope c56_cap_policy = "all" (soil now included; PR #904 applied). +## - Cap level c56_emis_cap_scenario = "none" -> p56_emis_cap = 1e6 = NON-BINDING. +## +## Soil-carbon bugfix PR #904 already applied to modules/59_som/{cellpool_jan23, +## static_jan19}/postsolve.gms. MACC linear fade-in added to +## modules/57_maccs/on_aug22/{input,declarations,preloop}.gms (gated by +## s57_maxmac_fadein; fadein=0 reproduces the flat baseline bit-for-bit). +## +## Run directly from this worktree (project folder renamed AlexKoberle, ASCII path +## -> renv no longer breaks; the separate magpie_nzb_run copy was retired). Input +## rev4.131 W3 already prepared in input/ (source_files.log matches) -> no download. +## --------------------------------------------------------------------------- + +library(lucode2) # setScenario lives in gms/lucode2 - load before use +library(gms) +library(magpie4) +source("config/default.cfg") +source("scripts/start_functions.R") + +# --- input data (rev4.131 W3, == Alex's runs) ------------------------------- +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) + +# --- do NOT download / recalibrate (proven config from prior runs) ---------- +cfg$force_download <- FALSE +cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE +cfg$recalibrate_landconversion_cost <- FALSE + +# --- climate OFF: bookkeeping convention (all 7 switches) ------------------- +cfg <- setScenario(cfg, "nocc") + +# --- run settings ----------------------------------------------------------- +cfg$title <- "nzb_R0_ref" +cfg$gms$ghg_policy <- "cap_apr26_reg" + +# cap: scope "all" (soil included; bug fixed); NON-BINDING (R0 reference) +cfg$gms$c56_cap_policy <- "all" +cfg$gms$c56_emis_cap_scenario <- "none" # p56_emis_cap = 1e6 -> never binds +cfg$gms$s56_source_bounds_on <- 0 + +# NO GHG prices (do not distort deforestation); no C-price-induced A/R +cfg$gms$c56_pollutant_prices <- "none" +cfg$gms$s56_c_price_induced_aff <- 0 + +# A/R via Half-Earth restoration, Brazil only (forced, phased 2025->2050) +cfg$gms$c22_protect_scenario <- "PBL_HalfEarth" +cfg$gms$c22_protect_scenario_noselect <- "none" +cfg$gms$policy_countries22 <- "BRA" +cfg$gms$s22_restore_land <- 1 + +# Non-CO2 via FIXED 1.5C MACC fade (step 1 @2025 -> 106 @2050, linear, 5 sources) +cfg$gms$s57_maxmac_fadein <- 1 +cfg$gms$s57_maxmac_fadein_start <- 2025 +cfg$gms$s57_maxmac_fadein_end <- 2050 +cfg$gms$s57_maxmac_n_soil <- 106 +cfg$gms$s57_maxmac_n_awms <- 106 +cfg$gms$s57_maxmac_ch4_rice <- 106 +cfg$gms$s57_maxmac_ch4_entferm <- 106 +cfg$gms$s57_maxmac_ch4_awms <- 106 + +cfg$gms$c_timesteps <- "5year2050" +cfg$output <- c("rds_report") +cfg$sequential <- FALSE + +start_run(cfg, codeCheck = FALSE) diff --git a/scripts/start/nzb_baseline_variants.R b/scripts/start/nzb_baseline_variants.R new file mode 100644 index 0000000000..2e20e23ace --- /dev/null +++ b/scripts/start/nzb_baseline_variants.R @@ -0,0 +1,74 @@ +## nzb_baseline_variants.R ------------------------------------------------------ +## Baseline (no-cap) sensitivities to complete the reference picture. All share +## the {off,off}-style baseline (no cap, restore off, WDPA base only, nocc, no GHG +## prices); they differ only in forest-policy stringency and MACC ceiling. +## +## 1. nzb_R0_offoff_polnone forest policy = none (no NPI) MACC off +## 2. nzb_R0_offoff_ndc forest policy = ndc MACC off +## 3. nzb_R0_npi_fullmacc forest = npi + FULL MACC (201) MACC full +## +## Forest policy = c32_aff_policy (afforestation) + c35_ad_policy (avoided defor) +## + c35_aolc_policy (avoided other-land conversion). +## "Full MACC potential" = s57_maxmac_* = 201 (max curve step ~1222 USD/tCO2eq) +## vs the library's 106 (~641 USD, the 1.5C price). fadein=1 kept (same phase-in). +## The NPI {off,off} no-cap baseline already exists (nzb_R0_mOFF_rOFF). +## All 3 fit one wave (<=6 on 24 GB). Output: rds_report. +## --------------------------------------------------------------------------- +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +# ---- common baseline config (no cap, restore off, no prices) --------------- +cfg$gms$ghg_policy <- "cap_apr26_reg" +cfg$gms$c56_cap_policy <- "all" +cfg$gms$c56_emis_cap_scenario <- "none" # non-binding (no cap) +cfg$gms$s56_emis_cap_parametric <- 0 # force OFF (input.gms drift guard) +cfg$gms$s56_source_bounds_on <- 0 +cfg$gms$c56_pollutant_prices <- "none" +cfg$gms$s56_c_price_induced_aff <- 0 +# restore off (baseline): WDPA base protection only +cfg$gms$c22_protect_scenario <- "none"; cfg$gms$s22_restore_land <- 0 +cfg$gms$c22_protect_scenario_noselect <- "none"; cfg$gms$policy_countries22 <- "BRA" +cfg$gms$c_timesteps <- "5year2050" +cfg$output <- c("rds_report") +cfg$sequential <- FALSE + +set_macc <- function(cfg, step){ # step (e.g. 106, 201) or -1 = off + cfg$gms$s57_maxmac_n_soil <- step; cfg$gms$s57_maxmac_n_awms <- step + cfg$gms$s57_maxmac_ch4_rice <- step; cfg$gms$s57_maxmac_ch4_entferm <- step + cfg$gms$s57_maxmac_ch4_awms <- step + cfg$gms$s57_maxmac_fadein <- if (step > 0) 1 else 0 + cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 + cfg +} +set_forest <- function(cfg, pol){ # "none" | "npi" | "ndc" + cfg$gms$c32_aff_policy <- pol + cfg$gms$c35_ad_policy <- pol + cfg$gms$c35_aolc_policy <- pol + cfg +} + +# variant | forest policy | macc step +variants <- list( + nzb_R0_offoff_polnone = list(forest = "none", macc = -1), + nzb_R0_offoff_ndc = list(forest = "ndc", macc = -1), + nzb_R0_npi_fullmacc = list(forest = "npi", macc = 201)) + +launch <- function(cfg, title, v){ + cfg <- set_forest(cfg, v$forest); cfg <- set_macc(cfg, v$macc) + cfg$title <- title + start_run(cfg, codeCheck = FALSE) + title +} +titles <- mapply(function(nm, v) launch(cfg, nm, v), names(variants), variants) +cat("== launched 3 baseline-variant runs ==\n"); print(unname(titles)) diff --git a/scripts/start/nzb_cap_extend_onon.R b/scripts/start/nzb_cap_extend_onon.R new file mode 100644 index 0000000000..0b0cf7da65 --- /dev/null +++ b/scripts/start/nzb_cap_extend_onon.R @@ -0,0 +1,70 @@ +## nzb_cap_extend_onon.R -------------------------------------------------------- +## Extend the {MACC on, restore on} cap ladder so the dashboard slider can span +## reported BRA AFOLU 2050 from ~-200 to ~+200 Mt. 4 NEW runs via the parametric +## switch (s56_emis_cap_parametric=1); no cs3 columns, no GAMS changes. +## +## capm200 600/400/200 -> -200 fixed ramp (matches existing grid; monotone) +## capm150 600/400/200 -> -150 fixed ramp +## cap200 600/467/333 -> +200 SCALED monotone waypoints (loose cap) +## cap300 600/500/400 -> +300 SCALED monotone waypoints +## +## Lower pair brackets reported -200; upper pair brackets reported +200 (reported +## ~ endpoint - ~50..77 offset; reported saturates at the no-cap ~277). Scaled +## waypoints = linear 600(2035) -> endpoint(2050) so the loose-cap path declines +## smoothly instead of dipping to 200 in 2045 then rebounding. +## All 4 fit one wave (<=6 on 24 GB). Output: rds_report. {on,on} levers only. +## --------------------------------------------------------------------------- +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +# ---- common cap config (== library) ---------------------------------------- +cfg$gms$ghg_policy <- "cap_apr26_reg" +cfg$gms$c56_cap_policy <- "all" +cfg$gms$s56_source_bounds_on <- 0 +cfg$gms$c56_pollutant_prices <- "none" +cfg$gms$s56_c_price_induced_aff <- 0 +cfg$gms$c_timesteps <- "5year2050" +cfg$output <- c("rds_report") +cfg$sequential <- FALSE + +# ---- {MACC on, restore on} levers (fixed across these 4 runs) -------------- +v <- 106 +cfg$gms$s57_maxmac_n_soil <- v; cfg$gms$s57_maxmac_n_awms <- v +cfg$gms$s57_maxmac_ch4_rice <- v; cfg$gms$s57_maxmac_ch4_entferm <- v +cfg$gms$s57_maxmac_ch4_awms <- v +cfg$gms$s57_maxmac_fadein <- 1 +cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 +cfg$gms$c22_protect_scenario <- "PBL_HalfEarth"; cfg$gms$s22_restore_land <- 1 +cfg$gms$c22_protect_scenario_noselect <- "none"; cfg$gms$policy_countries22 <- "BRA" + +# ---- parametric cap on; BRA-only via policy_countries56. The linear ramp from +# start_value (600 @ start_year) to the 2050 endpoint reproduces the scaled +# waypoints; only the endpoint differs per run. +cfg$gms$s56_emis_cap_parametric <- 1 +cfg$gms$s56_emis_cap_start_year <- 2035 +cfg$gms$s56_emis_cap_start_value <- 600 +cfg$gms$s56_emis_cap_target_year <- 2050 +cfg$gms$policy_countries56 <- "BRA" # parametric cap applies to this region only + +# capcol -> 2050 endpoint (Tg CO2eq/yr) +runs <- list(capm200 = -200, capm150 = -150, cap200 = 200, cap300 = 300) + +launch <- function(cfg, capcol, target){ + cfg$gms$s56_emis_cap_target <- target + cfg$title <- sprintf("nzb_lib_mON_rON_%s", capcol) + start_run(cfg, codeCheck = FALSE) + cfg$title +} +titles <- mapply(function(cc, t) launch(cfg, cc, t), names(runs), runs) +cat("== launched 4 extended {on,on} cap runs ==\n"); print(unname(titles)) diff --git a/scripts/start/nzb_nocap_corners.R b/scripts/start/nzb_nocap_corners.R new file mode 100644 index 0000000000..76f63f01d6 --- /dev/null +++ b/scripts/start/nzb_nocap_corners.R @@ -0,0 +1,63 @@ +## nzb_nocap_corners.R --------------------------------------------------------- +## The 3 MISSING no-cap (R0) references, one per lever corner that lacks one. +## {MACC on, restore on} already exists (nzb_R0_ref). This adds: +## nzb_R0_mON_rOFF (MACC on, restore off) +## nzb_R0_mOFF_rON (MACC off, restore on) +## nzb_R0_mOFF_rOFF (MACC off, restore off) +## Each = non-binding cap (c56_emis_cap_scenario "none" -> p56_emis_cap 1e6), so +## the dashboard's "no cap" reference matches the toggled corner exactly instead +## of falling back to the {on,on} R0. Same input/calibration as the library. +## All 3 fit one wave (<=6 on 24 GB). Output: rds_report. +## --------------------------------------------------------------------------- +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +# ---- common config (== library, but NON-BINDING cap) ----------------------- +cfg$gms$ghg_policy <- "cap_apr26_reg" +cfg$gms$c56_cap_policy <- "all" +cfg$gms$c56_emis_cap_scenario <- "none" # p56_emis_cap = 1e6 -> never binds +cfg$gms$s56_emis_cap_parametric <- 0 # force OFF (input.gms has drift from prior runs) +cfg$gms$s56_source_bounds_on <- 0 +cfg$gms$c56_pollutant_prices <- "none" +cfg$gms$s56_c_price_induced_aff <- 0 +cfg$gms$c_timesteps <- "5year2050" +cfg$output <- c("rds_report") +cfg$sequential <- FALSE + +apply_macc <- function(cfg, on){ + v <- if(on) 106 else -1 + cfg$gms$s57_maxmac_n_soil <- v; cfg$gms$s57_maxmac_n_awms <- v + cfg$gms$s57_maxmac_ch4_rice <- v; cfg$gms$s57_maxmac_ch4_entferm <- v + cfg$gms$s57_maxmac_ch4_awms <- v + cfg$gms$s57_maxmac_fadein <- if(on) 1 else 0 + cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 + cfg +} +apply_rest <- function(cfg, on){ + if(on){ cfg$gms$c22_protect_scenario <- "PBL_HalfEarth"; cfg$gms$s22_restore_land <- 1 } + else { cfg$gms$c22_protect_scenario <- "none"; cfg$gms$s22_restore_land <- 0 } + cfg$gms$c22_protect_scenario_noselect <- "none" + cfg$gms$policy_countries22 <- "BRA" + cfg +} +launch <- function(cfg, macc, rest){ + cfg <- apply_macc(cfg, macc); cfg <- apply_rest(cfg, rest) + cfg$title <- sprintf("nzb_R0_m%s_r%s", if(macc)"ON" else"OFF", if(rest)"ON" else"OFF") + start_run(cfg, codeCheck = FALSE) + cfg$title +} + +corners <- list(c(TRUE, FALSE), c(FALSE, TRUE), c(FALSE, FALSE)) # the 3 missing +titles <- sapply(corners, function(cc) launch(cfg, cc[1], cc[2])) +cat("== launched 3 no-cap corner runs ==\n"); print(unname(titles)) From 04301adf46f6bd0683076105302ac688f62b5324 Mon Sep 17 00:00:00 2001 From: florianh Date: Tue, 30 Jun 2026 22:59:50 +0200 Subject: [PATCH 2/8] youngsecdf: harvestable growing stock from the uncalibrated secdforest curve Young secondary forest on other land (youngsecdf) took its wood yield from the FRA-calibrated secdforest growing stock while its carbon followed the uncalibrated curve, letting the optimiser extract calibrated-level wood at near-zero booked carbon under any land-CO2 incentive. Add a dedicated im_growing_stock_ysf derived from the uncalibrated curve and feed it to the youngsecdf term of q35_prod_other, so wood yield and carbon are consistent. Addresses the PR #876 other-land wood-harvest known limitation. --- .../managementcalib_aug19/declarations.gms | 1 + .../managementcalib_aug19/presolve.gms | 20 +++++++++++++++++++ .../35_natveg/pot_forest_may24/equations.gms | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/modules/14_yields/managementcalib_aug19/declarations.gms b/modules/14_yields/managementcalib_aug19/declarations.gms index 4c76e17234..5b7398872f 100644 --- a/modules/14_yields/managementcalib_aug19/declarations.gms +++ b/modules/14_yields/managementcalib_aug19/declarations.gms @@ -15,6 +15,7 @@ parameters i14_lambda_yields(t,i,kcr) Scaling factor for non-linear management calibration (1) i14_managementcalib(t,j,kcr,w) Regional management calibration factor accounting for FAO yield levels (1) im_growing_stock(t,j,ac,land_timber) Harvestable stem biomass per ha by age class (tDM per ha) + im_growing_stock_ysf(t,j,ac) Harvestable stem biomass per ha by age class for young secondary forest on other land (tDM per ha) pm_yields_semi_calib(j,kve,w) Potential yields calibrated to FAO regional levels (tDM per ha per yr) i14_calib_yields_hist(i,w) Calibrated yields average over region and crop type at the historical reference year (tDM per ha per yr) i14_calib_yields_ratio(i) Irrigated to rainfed yield ratio for calibrated yields (1) diff --git a/modules/14_yields/managementcalib_aug19/presolve.gms b/modules/14_yields/managementcalib_aug19/presolve.gms index afdb33bcbe..faaecb4290 100644 --- a/modules/14_yields/managementcalib_aug19/presolve.gms +++ b/modules/14_yields/managementcalib_aug19/presolve.gms @@ -57,9 +57,29 @@ im_growing_stock(t,j,ac,"other") = ) ; +*' Young secondary forest on other land (`youngsecdf` in [35_natveg]) is forest +*' regrowth from natural succession. Its carbon stock follows the uncalibrated +*' natveg curve `pm_carbon_density_secdforest_ac_uncalib` (set in [52_carbon]), +*' NOT the FRA-calibrated secondary-forest curve. The harvestable growing stock +*' must be derived from the SAME (uncalibrated) curve so that wood yield and +*' carbon stock are consistent; using the calibrated `secdforest` growing stock +*' would decouple high wood yield from low booked carbon. The aboveground +*' fraction is that of secondary forest, because youngsecdf is forest biomass. + +im_growing_stock_ysf(t,j,ac) = + ( + pm_carbon_density_secdforest_ac_uncalib(t,j,ac,"vegc") + / sm_carbon_fraction + * fm_aboveground_fraction("secdforest") + / sum(clcl, pm_climate_class(j,clcl) * fm_ipcc_bef(clcl)) + ) + ; + *' @stop ** Hard constraint to always have a positive number in im_growing_stock im_growing_stock(t,j,ac,land_timber) = im_growing_stock(t,j,ac,land_timber)$(im_growing_stock(t,j,ac,land_timber) > 0) + 0.0001$(im_growing_stock(t,j,ac,land_timber) = 0); +im_growing_stock_ysf(t,j,ac) = im_growing_stock_ysf(t,j,ac)$(im_growing_stock_ysf(t,j,ac) > 0) + 0.0001$(im_growing_stock_ysf(t,j,ac) = 0); ** Set growing stock to 0 where it does not exceed a minimum for harvest im_growing_stock(t,j,ac,land_natveg)$(im_growing_stock(t,j,ac,land_natveg) < s14_minimum_growing_stock) = 0; +im_growing_stock_ysf(t,j,ac)$(im_growing_stock_ysf(t,j,ac) < s14_minimum_growing_stock) = 0; diff --git a/modules/35_natveg/pot_forest_may24/equations.gms b/modules/35_natveg/pot_forest_may24/equations.gms index d4b2542218..ee68c79cd0 100644 --- a/modules/35_natveg/pot_forest_may24/equations.gms +++ b/modules/35_natveg/pot_forest_may24/equations.gms @@ -163,7 +163,7 @@ q35_prod_other(j2).. sum(kforestry, vm_prod_natveg(j2,"other",kforestry)) =e= (sum(ac_sub, v35_hvarea_other(j2,"othernat",ac_sub) * sum(ct, im_growing_stock(ct,j2,ac_sub,"other"))) - + sum(ac_sub, v35_hvarea_other(j2,"youngsecdf",ac_sub) * sum(ct, im_growing_stock(ct,j2,ac_sub,"secdforest")))) + + sum(ac_sub, v35_hvarea_other(j2,"youngsecdf",ac_sub) * sum(ct, im_growing_stock_ysf(ct,j2,ac_sub)))) / m_timestep_length_forestry ; From 22936e5f08c1a8a2dd1c54f58b6e725acfc91297 Mon Sep 17 00:00:00 2001 From: florianh Date: Tue, 30 Jun 2026 23:05:04 +0200 Subject: [PATCH 3/8] emis_cap_reg: region-general forced wood self-sufficiency Generalize the BRA-only forced wood/woodfuel self-sufficiency switch into a region-selectable lever: s21_force_wood_selfsuff (default off) + policy_countries21 country selector with a superregion mask (a superregion is forced only if all its countries are selected via supreg/i_to_iso), replacing the hard-coded sameas(h,"BRA") guard. Mirrors policy_countries56. Suppresses wood-harvest trade leakage when a region's land-use emissions are constrained. Also drop the unused ov56_emis_co2eq output block in cap_apr26_reg/postsolve. --- config/default.cfg | 11 ++++++++ .../selfsuff_reduced/declarations.gms | 4 ++- .../21_trade/selfsuff_reduced/equations.gms | 4 +-- modules/21_trade/selfsuff_reduced/input.gms | 28 +++++++++++++++++++ modules/21_trade/selfsuff_reduced/preloop.gms | 24 +++++++++++++--- .../56_ghg_policy/cap_apr26_reg/postsolve.gms | 9 ------ 6 files changed, 64 insertions(+), 16 deletions(-) diff --git a/config/default.cfg b/config/default.cfg index a0a01d5a29..a6d722e5f1 100644 --- a/config/default.cfg +++ b/config/default.cfg @@ -707,6 +707,17 @@ cfg$gms$s21_trade_tariff_targetyear <- 2050 # * (inflated from default originally in USD05 using USD05 --> USD17 inflation rate:1.23) cfg$gms$s21_min_trade_margin_forestry <- 62 # def = 50 * 1.23 +# * Force full wood & woodfuel self-sufficiency for selected regions, to suppress +# * wood-harvest leakage when those regions' land-use emissions are constrained. +# * 1 = pin selected regions' wood/woodfuel production band to demand from sm_fix_SSP2 on +# * 0 = unchanged develop behaviour. Regions are chosen via policy_countries21 (a region is +# * forced only if ALL its countries are selected; no fully-selected region => no-op). +cfg$gms$s21_force_wood_selfsuff <- 0 # def = 0 +# * Countries whose (fully selected) region is forced to wood/woodfuel self-sufficiency +# * when s21_force_wood_selfsuff = 1. Default = all countries; narrow to a region's ISO +# * codes to target it (e.g. "BRA"). Mirrors policy_countries56 in module 56. +cfg$gms$policy_countries21 <- all_iso_countries # def = all_iso_countries + # ***--------------------- 22_land_conservation -------------------------------------- # * (area_based_apr22): Area-based conservation (baseline and future) diff --git a/modules/21_trade/selfsuff_reduced/declarations.gms b/modules/21_trade/selfsuff_reduced/declarations.gms index a81cf2fc7e..258ae9c85f 100644 --- a/modules/21_trade/selfsuff_reduced/declarations.gms +++ b/modules/21_trade/selfsuff_reduced/declarations.gms @@ -6,7 +6,9 @@ *** | Contact: magpie@pik-potsdam.de parameters - i21_trade_bal_reduction(t_all,k_trade) Trade balance reduction (1) + p21_country_switch(iso) Switch: country selected for forced wood self-sufficiency (1) + p21_selfsuff_region(h) Superregions forced to wood self-sufficiency (1=forced derived from policy_countries21) (1) + i21_trade_bal_reduction(t_all,h,k_trade) Trade balance reduction (1) i21_exp_shr(t_all,h,k_trade) Trade export shr (1) i21_trade_margin(h,k_trade) Trade margins (USD17MER per tDM) i21_trade_tariff(h,k_trade) Trade tariffs (USD17MER per tDM) diff --git a/modules/21_trade/selfsuff_reduced/equations.gms b/modules/21_trade/selfsuff_reduced/equations.gms index 0a0eeff8e8..cfb5f8f380 100644 --- a/modules/21_trade/selfsuff_reduced/equations.gms +++ b/modules/21_trade/selfsuff_reduced/equations.gms @@ -31,7 +31,7 @@ q21_trade_reg(h2,k_trade).. sum(supreg(h2,i2),vm_prod_reg(i2,k_trade)) =g= m21_baseline_production(vm_supply, v21_excess_prod, f21_self_suff) - * sum(ct,i21_trade_bal_reduction(ct,k_trade)) + * sum(ct,i21_trade_bal_reduction(ct,h2,k_trade)) - v21_import_for_feasibility(h2,k_trade); *' Upper bound for production. @@ -39,7 +39,7 @@ q21_trade_reg_up(h2,k_trade) .. sum(supreg(h2,i2),vm_prod_reg(i2,k_trade)) =l= m21_baseline_production(vm_supply, v21_excess_prod, f21_self_suff) - / sum(ct,i21_trade_bal_reduction(ct,k_trade)); + / sum(ct,i21_trade_bal_reduction(ct,h2,k_trade)); *' The global excess demand of each tradable good `v21_excess_demad` equals to *' the sum over all the imports of importing superregions. diff --git a/modules/21_trade/selfsuff_reduced/input.gms b/modules/21_trade/selfsuff_reduced/input.gms index 6cfe28dffd..0859350154 100644 --- a/modules/21_trade/selfsuff_reduced/input.gms +++ b/modules/21_trade/selfsuff_reduced/input.gms @@ -11,12 +11,40 @@ $setglobal c21_trade_liberalization l909090r808080 sets k_import21(k_trade) Commodities that can have additional imports to maintain feasibility / wood, woodfuel / + + policy_countries21(iso) countries whose (fully selected) region is forced to wood and woodfuel self-sufficiency + / ABW,AFG,AGO,AIA,ALA,ALB,AND,ARE,ARG,ARM, + ASM,ATA,ATF,ATG,AUS,AUT,AZE,BDI,BEL,BEN, + BES,BFA,BGD,BGR,BHR,BHS,BIH,BLM,BLR,BLZ, + BMU,BOL,BRA,BRB,BRN,BTN,BVT,BWA,CAF,CAN, + CCK,CHN,CHE,CHL,CIV,CMR,COD,COG,COK,COL, + COM,CPV,CRI,CUB,CUW,CXR,CYM,CYP,CZE,DEU, + DJI,DMA,DNK,DOM,DZA,ECU,EGY,ERI,ESH,ESP, + EST,ETH,FIN,FJI,FLK,FRA,FRO,FSM,GAB,GBR, + GEO,GGY,GHA,GIB,GIN,GLP,GMB,GNB,GNQ,GRC, + GRD,GRL,GTM,GUF,GUM,GUY,HKG,HMD,HND,HRV, + HTI,HUN,IDN,IMN,IND,IOT,IRL,IRN,IRQ,ISL, + ISR,ITA,JAM,JEY,JOR,JPN,KAZ,KEN,KGZ,KHM, + KIR,KNA,KOR,KWT,LAO,LBN,LBR,LBY,LCA,LIE, + LKA,LSO,LTU,LUX,LVA,MAC,MAF,MAR,MCO,MDA, + MDG,MDV,MEX,MHL,MKD,MLI,MLT,MMR,MNE,MNG, + MNP,MOZ,MRT,MSR,MTQ,MUS,MWI,MYS,MYT,NAM, + NCL,NER,NFK,NGA,NIC,NIU,NLD,NOR,NPL,NRU, + NZL,OMN,PAK,PAN,PCN,PER,PHL,PLW,PNG,POL, + PRI,PRK,PRT,PRY,PSE,PYF,QAT,REU,ROU,RUS, + RWA,SAU,SDN,SEN,SGP,SGS,SHN,SJM,SLB,SLE, + SLV,SMR,SOM,SPM,SRB,SSD,STP,SUR,SVK,SVN, + SWE,SWZ,SXM,SYC,SYR,TCA,TCD,TGO,THA,TJK, + TKL,TKM,TLS,TON,TTO,TUN,TUR,TUV,TWN,TZA, + UGA,UKR,UMI,URY,USA,UZB,VAT,VCT,VEN,VGB, + VIR,VNM,VUT,WLF,WSM,YEM,ZAF,ZMB,ZWE / ; scalars s21_trade_tariff Trade tariff switch (1=on 0=off) (1) / 1 / s21_cost_import Cost for additional imports to maintain feasibility (USD17MER per tDM) / 1500 / s21_min_trade_margin_forestry Minimum trade margin for forestry products (USD17MER per tDM) / 62 / + s21_force_wood_selfsuff Force full wood and woodfuel self-sufficiency for the regions selected via policy_countries21 (1=on 0=off) (1) / 0 / ; table f21_trade_bal_reduction(t_all,trade_groups21,trade_regime21) Share of inelastic trade pool (1) diff --git a/modules/21_trade/selfsuff_reduced/preloop.gms b/modules/21_trade/selfsuff_reduced/preloop.gms index 8a1bfb2f5c..0e60460af8 100644 --- a/modules/21_trade/selfsuff_reduced/preloop.gms +++ b/modules/21_trade/selfsuff_reduced/preloop.gms @@ -10,14 +10,30 @@ *' with sm_fix_SSP2 to keep values matching historical data until then. loop(t_all, if(m_year(t_all) <= sm_fix_SSP2, - i21_trade_bal_reduction(t_all,k_trade)=f21_trade_bal_reduction(t_all,"easytrade","l909090r808080"); - i21_trade_bal_reduction(t_all,k_hardtrade21)=f21_trade_bal_reduction(t_all,"hardtrade","l909090r808080"); + i21_trade_bal_reduction(t_all,h,k_trade)=f21_trade_bal_reduction(t_all,"easytrade","l909090r808080"); + i21_trade_bal_reduction(t_all,h,k_hardtrade21)=f21_trade_bal_reduction(t_all,"hardtrade","l909090r808080"); else - i21_trade_bal_reduction(t_all,k_trade)=f21_trade_bal_reduction(t_all,"easytrade","%c21_trade_liberalization%"); -i21_trade_bal_reduction(t_all,k_hardtrade21)=f21_trade_bal_reduction(t_all,"hardtrade","%c21_trade_liberalization%"); + i21_trade_bal_reduction(t_all,h,k_trade)=f21_trade_bal_reduction(t_all,"easytrade","%c21_trade_liberalization%"); +i21_trade_bal_reduction(t_all,h,k_hardtrade21)=f21_trade_bal_reduction(t_all,"hardtrade","%c21_trade_liberalization%"); ); ); +*' Optionally force full wood & woodfuel self-sufficiency for the regions selected +*' via policy_countries21, to suppress wood-harvest leakage when those regions' +*' land-use emissions are constrained. s21_force_wood_selfsuff = 1 pins +*' the selected regions' wood/woodfuel production band to baseline demand (trade +*' balance reduction = 1) from sm_fix_SSP2 onwards; = 0 reproduces unchanged develop +*' behaviour. A region is forced only if ALL its countries are in policy_countries21 +*' (forcing self-sufficiency on a partial superregion is not meaningful), mirroring +*' the region mask in module 56. A superregion h is forced only if every country in +*' every region it contains (supreg(h,i), i_to_iso(i,iso)) is in policy_countries21; +*' empty / no fully-selected superregion makes it a no-op. +p21_country_switch(iso) = 0; +p21_country_switch(policy_countries21) = 1; +p21_selfsuff_region(h) = 1$(sum((supreg(h,i), i_to_iso(i,iso)), 1 - p21_country_switch(iso)) = 0); +i21_trade_bal_reduction(t_all,h,"wood")$(s21_force_wood_selfsuff = 1 AND p21_selfsuff_region(h) AND m_year(t_all) > sm_fix_SSP2) = 1; +i21_trade_bal_reduction(t_all,h,"woodfuel")$(s21_force_wood_selfsuff = 1 AND p21_selfsuff_region(h) AND m_year(t_all) > sm_fix_SSP2) = 1; + i21_exports(t_all,h,k_trade) = ((f21_self_suff(t_all,h,k_trade) * f21_dom_supply(t_all,h,k_trade)) - f21_dom_supply(t_all,h,k_trade))$(f21_self_suff(t_all,h,k_trade) > 1); i21_exp_glo(t_all,k_trade) = sum(h, i21_exports(t_all,h,k_trade)); i21_exp_shr(t_all,h,k_trade) = i21_exports(t_all,h,k_trade) / (i21_exp_glo(t_all,k_trade) + 0.001$(i21_exp_glo(t_all,k_trade) = 0)); diff --git a/modules/56_ghg_policy/cap_apr26_reg/postsolve.gms b/modules/56_ghg_policy/cap_apr26_reg/postsolve.gms index 52ac3cdecc..a648f9e9b7 100644 --- a/modules/56_ghg_policy/cap_apr26_reg/postsolve.gms +++ b/modules/56_ghg_policy/cap_apr26_reg/postsolve.gms @@ -22,7 +22,6 @@ p56_emis_cap_slack(t,i) = v56_slack_emis_cap.l(i); ov56_emission_cost(t,i,emis_source,"marginal") = v56_emission_cost.m(i,emis_source); ov_reward_cdr_aff(t,i,"marginal") = vm_reward_cdr_aff.m(i); ov56_reward_cdr_aff(t,j,"marginal") = v56_reward_cdr_aff.m(j); - ov56_emis_co2eq(t,i,emis_source,pollutants,"marginal") = 0; oq56_emission_costs(t,i,"marginal") = q56_emission_costs.m(i); oq56_emission_cost_annual(t,i,emis_annual,"marginal") = q56_emission_cost_annual.m(i,emis_annual); oq56_emission_cost_oneoff(t,i,emis_oneoff,"marginal") = q56_emission_cost_oneoff.m(i,emis_oneoff); @@ -39,12 +38,6 @@ p56_emis_cap_slack(t,i) = v56_slack_emis_cap.l(i); ov56_emission_cost(t,i,emis_source,"level") = v56_emission_cost.l(i,emis_source); ov_reward_cdr_aff(t,i,"level") = vm_reward_cdr_aff.l(i); ov56_reward_cdr_aff(t,j,"level") = v56_reward_cdr_aff.l(j); -*' ov56_emis_co2eq: CO2eq computed from solved emissions, GWP factors and cap mask. -*' Only "level" is meaningful; marginal/upper/lower are set to 0. - ov56_emis_co2eq(t,i,emis_source,pollutants,"level") = - vm_emissions_reg.l(i,emis_source,pollutants) - * p56_gwp(pollutants) - * p56_cap_mask(emis_source,pollutants); oq56_emission_costs(t,i,"level") = q56_emission_costs.l(i); oq56_emission_cost_annual(t,i,emis_annual,"level") = q56_emission_cost_annual.l(i,emis_annual); oq56_emission_cost_oneoff(t,i,emis_oneoff,"level") = q56_emission_cost_oneoff.l(i,emis_oneoff); @@ -61,7 +54,6 @@ p56_emis_cap_slack(t,i) = v56_slack_emis_cap.l(i); ov56_emission_cost(t,i,emis_source,"upper") = v56_emission_cost.up(i,emis_source); ov_reward_cdr_aff(t,i,"upper") = vm_reward_cdr_aff.up(i); ov56_reward_cdr_aff(t,j,"upper") = v56_reward_cdr_aff.up(j); - ov56_emis_co2eq(t,i,emis_source,pollutants,"upper") = 0; oq56_emission_costs(t,i,"upper") = q56_emission_costs.up(i); oq56_emission_cost_annual(t,i,emis_annual,"upper") = q56_emission_cost_annual.up(i,emis_annual); oq56_emission_cost_oneoff(t,i,emis_oneoff,"upper") = q56_emission_cost_oneoff.up(i,emis_oneoff); @@ -78,7 +70,6 @@ p56_emis_cap_slack(t,i) = v56_slack_emis_cap.l(i); ov56_emission_cost(t,i,emis_source,"lower") = v56_emission_cost.lo(i,emis_source); ov_reward_cdr_aff(t,i,"lower") = vm_reward_cdr_aff.lo(i); ov56_reward_cdr_aff(t,j,"lower") = v56_reward_cdr_aff.lo(j); - ov56_emis_co2eq(t,i,emis_source,pollutants,"lower") = 0; oq56_emission_costs(t,i,"lower") = q56_emission_costs.lo(i); oq56_emission_cost_annual(t,i,emis_annual,"lower") = q56_emission_cost_annual.lo(i,emis_annual); oq56_emission_cost_oneoff(t,i,emis_oneoff,"lower") = q56_emission_cost_oneoff.lo(i,emis_oneoff); From d5e6b4f8f49fd2074ae53806538540bf3b1755ae Mon Sep 17 00:00:00 2001 From: florianh Date: Wed, 1 Jul 2026 09:14:40 +0200 Subject: [PATCH 4/8] nzb: add comprehensive HPC test grid start script (light tier) One start script -> 49 SLURM jobs on the PIK HPC, all cap_apr26_reg / nocc / AR6 GWP / forced BRA wood self-sufficiency, indexed on achieved reported GWP100AR6|Land BRA AFOLU 2050: Fam C conservation {WDPA, 30by30, HalfEarth} x cap ladder (cap alone) Fam A BRA capped + RoW 2C price; global context {A/R + 2nd-gen bioenergy} toggled on/off together Fam B cap + BRA 1.5C price driving price-induced A/R + price-driven MACC anchor NPI only Tier-switchable (light/medium) via 2 lines; horizon via c_timesteps. --- scripts/start/nzb_hpc_grid.R | 151 +++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 scripts/start/nzb_hpc_grid.R diff --git a/scripts/start/nzb_hpc_grid.R b/scripts/start/nzb_hpc_grid.R new file mode 100644 index 0000000000..bac38e9bba --- /dev/null +++ b/scripts/start/nzb_hpc_grid.R @@ -0,0 +1,151 @@ +## nzb_hpc_grid.R =============================================================== +## Comprehensive NZB test grid for the PIK HPC (SLURM). One start script; each +## start_run() -> one SLURM job. Launch on the LOGIN node with submit=direct. +## +## PREREQUISITE (run ONCE on login first, to warm the input cache and avoid the +## H12-fallback trap): Rscript scripts/start/download_data_BRA.R +## then verify core/sets.gms shows `Regionscode: 5638d5dc` + 13 regions (incl. BRA). +## +## Launch: Rscript start.R runscripts=nzb_hpc_grid submit=direct +## +## ---- TIER SWITCHES (edit these 2 lines to flip medium <-> light) ------------------- +## medium (~71 runs): STEP_AB=50 ; B_AR=c(TRUE,FALSE) +## light (~49 runs): STEP_AB=100; B_AR=c(TRUE) +STEP_AB <- 100 # cap-ladder step for families A & B (C is always 50) [LIGHT] +B_AR <- c(TRUE) # A/R on/off in family B [LIGHT] +## ------------------------------------------------------------------------------------ +## +## DESIGN (indexed by ACHIEVED reported GWP100AR6|Land BRA AFOLU 2050; nocc; AR6 GWP +## baked into cap_apr26_reg/preloop.gms; wood self-sufficiency forced for BRA): +## Spine : parametric BRA cap, reported ladder {-200..+200} (cap target = reported+71; +## dashboard re-indexes on achieved). +## Fam C : conservation {WDPA, 30by30, HalfEarth} x cap ladder + ref. Cap ALONE +## (forced 1.5C MACC, no price). HalfEarth = current dashboard corner (redo). +## Fam A : global-policy context. RoW priced 2C (PkBudg1000, noselect); BRA capped. +## Global context {A/R (RoW aff) + 2nd-gen bioenergy demand} toggled ON/OFF +## together. Cons=HalfEarth. +## Fam B : cap PLUS a BRA 1.5C CO2 price (PkBudg650) driving price-induced A/R and +## price-driven MACC; A/R on/off. Cons=HalfEarth. Tests whether the price +## deepens CO2 below the cap alone (compare B vs C-HalfEarth). +## Anchor: NPI only, no MACC/restore/price/cap ("do nothing"). +## +## Cap families (C, A) force 1.5C MACC (BRA has no own price). Family B is price-driven. +## A/R (s56_c_price_induced_aff) only bites where a price applies: RoW in A, BRA in B. +## ============================================================================ +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +# ---- input + infra (BRA-H13 W3; on HPC download_distribute falls back to local mirrors) ---- +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +# ---- common GHG-policy / trade / horizon (all runs) -------------------------------- +cfg$gms$ghg_policy <- "cap_apr26_reg" # AR6 GWP baked in (preloop.gms:131-133) +cfg$gms$c56_cap_policy <- "all" # soil incl. (PR #904) +cfg$gms$s56_source_bounds_on <- 0 +cfg$gms$policy_countries56 <- "BRA" +cfg$gms$s21_force_wood_selfsuff <- 1 # forced BRA wood self-sufficiency (no leakage) +cfg$gms$policy_countries21 <- "BRA" +cfg$gms$c32_aff_policy <- "npi"; cfg$gms$c35_ad_policy <- "npi"; cfg$gms$c35_aolc_policy <- "npi" +cfg$gms$c_timesteps <- "5year2050" # <-- HORIZON knob: "coup2100" for 2100 +cfg$output <- c("rds_report") +cfg$sequential <- FALSE +cfg$qos <- "standby" # many runs > priority MaxJobsPU cap + +CAPOFFSET <- 71 # reported = cap - 71 (wood-SS on) +reps_main <- seq(-200, 200, by = 50) # family C ladder +reps_ab <- seq(-200, 200, by = STEP_AB) # families A & B ladder + +reptag <- function(r) if (r == 0) "rep000" else sprintf("rep%s%03d", if (r < 0) "M" else "P", abs(r)) +launch <- function(cfg, title) { cfg$title <- title; start_run(cfg, codeCheck = FALSE) } + +# ---- lever helpers ----------------------------------------------------------------- +macc_forced <- function(cfg) { # forced 1.5C MACC, faded 2025->2050 + for (s in c("n_soil","n_awms","ch4_rice","ch4_entferm","ch4_awms")) + cfg$gms[[paste0("s57_maxmac_", s)]] <- 106 + cfg$gms$s57_maxmac_fadein <- 1 + cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 + cfg +} +macc_pricedriven <- function(cfg) { # abatement follows the CO2 price + for (s in c("n_soil","n_awms","ch4_rice","ch4_entferm","ch4_awms")) + cfg$gms[[paste0("s57_maxmac_", s)]] <- -1 + cfg$gms$s57_maxmac_fadein <- 0 + cfg +} +conservation <- function(cfg, scen) { # "none"(=WDPA base) / "30by30" / "PBL_HalfEarth" + cfg$gms$c22_protect_scenario <- scen + cfg$gms$c22_protect_scenario_noselect <- "none" + cfg$gms$s22_restore_land <- if (scen == "none") 0 else 1 + cfg$gms$policy_countries22 <- "BRA" + cfg +} +set_cap <- function(cfg, reported) { + cfg$gms$s56_emis_cap_parametric <- 1 + cfg$gms$s56_emis_cap_start_year <- 2035 + cfg$gms$s56_emis_cap_start_value <- 600 + cfg$gms$s56_emis_cap_target_year <- 2050 + cfg$gms$s56_emis_cap_target <- reported + CAPOFFSET + cfg +} +set_nocap <- function(cfg) { + cfg$gms$s56_emis_cap_parametric <- 0; cfg$gms$c56_emis_cap_scenario <- "none"; cfg +} +ladder <- function(base, fam, reps) { # ref (no-cap) + cap ladder + launch(set_nocap(base), sprintf("nzb_%s_ref", fam)) + for (r in reps) launch(set_cap(base, r), sprintf("nzb_%s_%s", fam, reptag(r))) +} + +# ============================ Family C: conservation (cap alone) ==================== +for (cons in list(list(tag="wdpa", scen="none"), + list(tag="30by30", scen="30by30"), + list(tag="half", scen="PBL_HalfEarth"))) { + base <- conservation(macc_forced(cfg), cons$scen) + base$gms$c56_pollutant_prices <- "none" + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" + base$gms$s56_c_price_induced_aff <- 0 + ladder(base, sprintf("gC_%s", cons$tag), reps_main) +} + +# ===================== Family A: global-policy context (RoW priced 2C) ============== +# A/R (RoW afforestation) + 2nd-gen bioenergy demand toggled ON/OFF together. +for (ctx in c(TRUE, FALSE)) { + base <- conservation(macc_forced(cfg), "PBL_HalfEarth") + base$gms$c56_pollutant_prices <- "none" # BRA capped + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C + base$gms$s56_c_price_induced_aff <- if (ctx) 1 else 0 + bioscen <- if (ctx) "R34M410-SSP2-PkBudg1000" else "none" + base$gms$c60_2ndgen_biodem <- bioscen + base$gms$c60_2ndgen_biodem_noselect <- bioscen + ladder(base, sprintf("gA_ctx%s", if (ctx) "ON" else "OFF"), reps_ab) +} + +# ===================== Family B: cap + BRA 1.5C price (drives A/R + MACC) ============ +for (ar in B_AR) { + base <- conservation(macc_pricedriven(cfg), "PBL_HalfEarth") + base$gms$c56_pollutant_prices <- "R34M410-SSP2-PkBudg650" # BRA priced 1.5C + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" # RoW current policies + base$gms$s56_c_price_induced_aff <- if (ar) 1 else 0 + ladder(base, sprintf("gB_ar%s", if (ar) "ON" else "OFF"), reps_ab) +} + +# ===================== Anchor: NPI only (no MACC / restore / price / cap) ============ +anchor <- set_nocap(conservation(macc_pricedriven(cfg), "none")) +anchor$gms$c56_pollutant_prices <- "none" +anchor$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" +anchor$gms$s56_c_price_induced_aff <- 0 +launch(anchor, "nzb_g0_npi") + +nC <- 3 * (length(reps_main) + 1) +nA <- 2 * (length(reps_ab) + 1) +nB <- length(B_AR) * (length(reps_ab) + 1) +cat(sprintf("== nzb_hpc_grid launched: C(%d) + A(%d) + B(%d) + anchor(1) = %d SLURM jobs ==\n", + nC, nA, nB, nC + nA + nB + 1)) From de81210e72742a3fe4f6a915f5156b1b928fad3c Mon Sep 17 00:00:00 2001 From: florianh Date: Wed, 1 Jul 2026 13:03:27 +0200 Subject: [PATCH 5/8] nzb grid: Family A RoW-only bioenergy + FAMILIES subset switch Family A ('BRA does not act alone') now applies the 2C context (price + price-induced A/R + 2nd-gen bioenergy demand) to the REST OF WORLD only: BRA stays capped/unpriced with BASELINE bioenergy demand (NPi2025; in NZB BRA's bioenergy comes from MACRO). Implemented via scen_countries60=BRA so the region split mirrors policy_countries56. Collapses to one gA_RoW2C ladder ('context-off' == Family C HalfEarth). Adds NZB_FAMILIES env switch to re-run a subset (e.g. NZB_FAMILIES=A) without touching C/B/anchor. --- scripts/start/nzb_hpc_grid.R | 66 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/scripts/start/nzb_hpc_grid.R b/scripts/start/nzb_hpc_grid.R index bac38e9bba..cf28c6d70b 100644 --- a/scripts/start/nzb_hpc_grid.R +++ b/scripts/start/nzb_hpc_grid.R @@ -7,12 +7,15 @@ ## then verify core/sets.gms shows `Regionscode: 5638d5dc` + 13 regions (incl. BRA). ## ## Launch: Rscript start.R runscripts=nzb_hpc_grid submit=direct +## re-run a subset: NZB_FAMILIES=A Rscript start.R runscripts=nzb_hpc_grid submit=direct ## ## ---- TIER SWITCHES (edit these 2 lines to flip medium <-> light) ------------------- -## medium (~71 runs): STEP_AB=50 ; B_AR=c(TRUE,FALSE) -## light (~49 runs): STEP_AB=100; B_AR=c(TRUE) +## medium (~63 runs): STEP_AB=50 ; B_AR=c(TRUE,FALSE) +## light (~43 runs): STEP_AB=100; B_AR=c(TRUE) STEP_AB <- 100 # cap-ladder step for families A & B (C is always 50) [LIGHT] B_AR <- c(TRUE) # A/R on/off in family B [LIGHT] +## which families to run (env override for partial re-runs); default = all +FAMILIES <- strsplit(Sys.getenv("NZB_FAMILIES", "C,A,B,0"), ",")[[1]] ## ------------------------------------------------------------------------------------ ## ## DESIGN (indexed by ACHIEVED reported GWP100AR6|Land BRA AFOLU 2050; nocc; AR6 GWP @@ -21,9 +24,11 @@ B_AR <- c(TRUE) # A/R on/off in family B ## dashboard re-indexes on achieved). ## Fam C : conservation {WDPA, 30by30, HalfEarth} x cap ladder + ref. Cap ALONE ## (forced 1.5C MACC, no price). HalfEarth = current dashboard corner (redo). -## Fam A : global-policy context. RoW priced 2C (PkBudg1000, noselect); BRA capped. -## Global context {A/R (RoW aff) + 2nd-gen bioenergy demand} toggled ON/OFF -## together. Cons=HalfEarth. +## Fam A : "BRA does not act alone" - RoW pursues 2C (PkBudg1000 price + price-induced +## A/R + 2C 2nd-gen bioenergy demand); BRA capped, unpriced, and BRA's own +## bioenergy demand held at BASELINE (NPi2025; in NZB it comes from MACRO). +## RoW-only via policy_countries56 / scen_countries60 = BRA split. Cons=HalfEarth. +## 'context-off' == Family C HalfEarth (RoW at current policies), so not re-run. ## Fam B : cap PLUS a BRA 1.5C CO2 price (PkBudg650) driving price-induced A/R and ## price-driven MACC; A/R on/off. Cons=HalfEarth. Tests whether the price ## deepens CO2 below the cap alone (compare B vs C-HalfEarth). @@ -57,6 +62,7 @@ cfg$gms$policy_countries21 <- "BRA" cfg$gms$c32_aff_policy <- "npi"; cfg$gms$c35_ad_policy <- "npi"; cfg$gms$c35_aolc_policy <- "npi" cfg$gms$c_timesteps <- "5year2050" # <-- HORIZON knob: "coup2100" for 2100 cfg$output <- c("rds_report") +cfg$results_folder <- "output/:title:" # undated folders (drops :date:) -> stable names cfg$sequential <- FALSE cfg$qos <- "standby" # many runs > priority MaxJobsPU cap @@ -105,9 +111,9 @@ ladder <- function(base, fam, reps) { # ref (no-cap) + cap ladder } # ============================ Family C: conservation (cap alone) ==================== -for (cons in list(list(tag="wdpa", scen="none"), - list(tag="30by30", scen="30by30"), - list(tag="half", scen="PBL_HalfEarth"))) { +if ("C" %in% FAMILIES) for (cons in list(list(tag="wdpa", scen="none"), + list(tag="30by30", scen="30by30"), + list(tag="half", scen="PBL_HalfEarth"))) { base <- conservation(macc_forced(cfg), cons$scen) base$gms$c56_pollutant_prices <- "none" base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" @@ -115,21 +121,20 @@ for (cons in list(list(tag="wdpa", scen="none"), ladder(base, sprintf("gC_%s", cons$tag), reps_main) } -# ===================== Family A: global-policy context (RoW priced 2C) ============== -# A/R (RoW afforestation) + 2nd-gen bioenergy demand toggled ON/OFF together. -for (ctx in c(TRUE, FALSE)) { +# ===================== Family A: RoW pursues 2C, BRA capped (BRA bioen baseline) ===== +if ("A" %in% FAMILIES) { base <- conservation(macc_forced(cfg), "PBL_HalfEarth") - base$gms$c56_pollutant_prices <- "none" # BRA capped - base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C - base$gms$s56_c_price_induced_aff <- if (ctx) 1 else 0 - bioscen <- if (ctx) "R34M410-SSP2-PkBudg1000" else "none" - base$gms$c60_2ndgen_biodem <- bioscen - base$gms$c60_2ndgen_biodem_noselect <- bioscen - ladder(base, sprintf("gA_ctx%s", if (ctx) "ON" else "OFF"), reps_ab) + base$gms$c56_pollutant_prices <- "none" # BRA capped, not priced + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C price + base$gms$s56_c_price_induced_aff <- 1 # price-induced A/R (RoW) + base$gms$scen_countries60 <- "BRA" # split BRA vs RoW bioenergy + base$gms$c60_2ndgen_biodem <- "R34M410-SSP2-NPi2025" # BRA baseline (MACRO in NZB) + base$gms$c60_2ndgen_biodem_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C bioenergy demand + ladder(base, "gA_RoW2C", reps_ab) } # ===================== Family B: cap + BRA 1.5C price (drives A/R + MACC) ============ -for (ar in B_AR) { +if ("B" %in% FAMILIES) for (ar in B_AR) { base <- conservation(macc_pricedriven(cfg), "PBL_HalfEarth") base$gms$c56_pollutant_prices <- "R34M410-SSP2-PkBudg650" # BRA priced 1.5C base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" # RoW current policies @@ -138,14 +143,17 @@ for (ar in B_AR) { } # ===================== Anchor: NPI only (no MACC / restore / price / cap) ============ -anchor <- set_nocap(conservation(macc_pricedriven(cfg), "none")) -anchor$gms$c56_pollutant_prices <- "none" -anchor$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" -anchor$gms$s56_c_price_induced_aff <- 0 -launch(anchor, "nzb_g0_npi") +if ("0" %in% FAMILIES) { + anchor <- set_nocap(conservation(macc_pricedriven(cfg), "none")) + anchor$gms$c56_pollutant_prices <- "none" + anchor$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" + anchor$gms$s56_c_price_induced_aff <- 0 + launch(anchor, "nzb_g0_npi") +} -nC <- 3 * (length(reps_main) + 1) -nA <- 2 * (length(reps_ab) + 1) -nB <- length(B_AR) * (length(reps_ab) + 1) -cat(sprintf("== nzb_hpc_grid launched: C(%d) + A(%d) + B(%d) + anchor(1) = %d SLURM jobs ==\n", - nC, nA, nB, nC + nA + nB + 1)) +nC <- if ("C" %in% FAMILIES) 3 * (length(reps_main) + 1) else 0 +nA <- if ("A" %in% FAMILIES) 1 * (length(reps_ab) + 1) else 0 +nB <- if ("B" %in% FAMILIES) length(B_AR) * (length(reps_ab) + 1) else 0 +n0 <- if ("0" %in% FAMILIES) 1 else 0 +cat(sprintf("== nzb_hpc_grid launched [%s]: C(%d)+A(%d)+B(%d)+anchor(%d) = %d jobs ==\n", + paste(FAMILIES, collapse=","), nC, nA, nB, n0, nC + nA + nB + n0)) From 08fd6f5fb15a5cd9f007e180c9cfa7fc027e0f93 Mon Sep 17 00:00:00 2001 From: florianh Date: Thu, 2 Jul 2026 21:30:39 +0200 Subject: [PATCH 6/8] module 21 (selfsuff_reduced): generalized minimum self-sufficiency floor Replace the wood-only s21_force_wood_selfsuff pin with a general, region- and commodity-flexible minimum self-sufficiency FLOOR. - New equation q21_min_selfsuff: superregional production >= i21_min_selfsuff * demand -- a one-sided lower bound (raises self-sufficiency where it binds, does not cap the upper side; unlike the old two-sided i21_trade_bal_reduction pin). - i21_min_selfsuff = s21_forcesuff_value * f21_self_suff for the commodities in forcesuff21 and the regions in policy_countries21, from sm_fix_SSP2 onward. Anchored to the time-constant input f21_self_suff, so it freezes each commodity's 2025 export/import intensity -- no baseline run needed. - New switches: s21_force_selfsuff (on/off), forcesuff21 (subset of k_trade, empty by default), s21_forcesuff_value (fraction of the 2025 self-sufficiency held). - Removes s21_force_wood_selfsuff; wood/woodfuel self-sufficiency is now obtained by listing them in forcesuff21 (floor == pin for wood under a cap, since the binding side is always the lower bound). - nzb_hpc_grid.R updated to the new switch. Empty forcesuff21 / s21_force_selfsuff = 0 reproduces develop behaviour bit-for-bit. codeCheck-clean; compiles (gams main.gms action=c). --- config/default.cfg | 30 +++++++++++++------ .../selfsuff_reduced/declarations.gms | 7 +++-- .../21_trade/selfsuff_reduced/equations.gms | 11 +++++++ modules/21_trade/selfsuff_reduced/input.gms | 8 +++-- .../21_trade/selfsuff_reduced/postsolve.gms | 4 +++ modules/21_trade/selfsuff_reduced/preloop.gms | 28 +++++++++-------- scripts/start/nzb_hpc_grid.R | 3 +- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/config/default.cfg b/config/default.cfg index a6d722e5f1..b49dbbca1e 100644 --- a/config/default.cfg +++ b/config/default.cfg @@ -707,17 +707,29 @@ cfg$gms$s21_trade_tariff_targetyear <- 2050 # * (inflated from default originally in USD05 using USD05 --> USD17 inflation rate:1.23) cfg$gms$s21_min_trade_margin_forestry <- 62 # def = 50 * 1.23 -# * Force full wood & woodfuel self-sufficiency for selected regions, to suppress -# * wood-harvest leakage when those regions' land-use emissions are constrained. -# * 1 = pin selected regions' wood/woodfuel production band to demand from sm_fix_SSP2 on -# * 0 = unchanged develop behaviour. Regions are chosen via policy_countries21 (a region is -# * forced only if ALL its countries are selected; no fully-selected region => no-op). -cfg$gms$s21_force_wood_selfsuff <- 0 # def = 0 -# * Countries whose (fully selected) region is forced to wood/woodfuel self-sufficiency -# * when s21_force_wood_selfsuff = 1. Default = all countries; narrow to a region's ISO -# * codes to target it (e.g. "BRA"). Mirrors policy_countries56 in module 56. +# * ISO codes of the region(s) subject to the self-sufficiency floor below (e.g. "BRA"); +# * default = all countries. Works exactly like policy_countries56: a region is included +# * only if all of its countries are listed, because the trade balance (like the cap) is a +# * hard region-level constraint and can't apply to only part of a region. cfg$gms$policy_countries21 <- all_iso_countries # def = all_iso_countries +# * Minimum self-sufficiency floor: require production >= s21_forcesuff_value * +# * f21_self_suff * demand for the commodities in forcesuff21, in the regions selected +# * via policy_countries21, from sm_fix_SSP2 onwards. One-sided floor (binds only from +# * below). This subsumes the former wood-only switch: to force wood/woodfuel +# * self-sufficiency, include them in forcesuff21. 1 = on, 0 = unchanged develop behaviour. +cfg$gms$s21_force_selfsuff <- 0 # def = 0 +# * Commodities subject to the floor (subset of k_trade). Empty by default (no-op); +# * populate to protect exports, e.g. for BRA net exporters: +# * "wood, woodfuel, soybean, oilcakes, oils, maiz, sugar, livst_rum, livst_chick". +cfg$gms$forcesuff21 <- "" # def = empty (no commodities) +# * Retention fraction of the 2025 baseline self-sufficiency (production / demand), +# * held as a floor for every future timestep when s21_force_selfsuff = 1. The floor +# * tracks f21_self_suff (constant over time), so it holds each commodity's 2025 +# * export/import intensity. No baseline run needed. +# * 1 = freeze exactly at 2025; 0.9 = allow at most ~10% erosion below 2025. +cfg$gms$s21_forcesuff_value <- 1 # def = 1 + # ***--------------------- 22_land_conservation -------------------------------------- # * (area_based_apr22): Area-based conservation (baseline and future) diff --git a/modules/21_trade/selfsuff_reduced/declarations.gms b/modules/21_trade/selfsuff_reduced/declarations.gms index 258ae9c85f..a9aa60e10b 100644 --- a/modules/21_trade/selfsuff_reduced/declarations.gms +++ b/modules/21_trade/selfsuff_reduced/declarations.gms @@ -6,8 +6,9 @@ *** | Contact: magpie@pik-potsdam.de parameters - p21_country_switch(iso) Switch: country selected for forced wood self-sufficiency (1) - p21_selfsuff_region(h) Superregions forced to wood self-sufficiency (1=forced derived from policy_countries21) (1) + p21_country_switch(iso) Switch: country selected for the forced self-sufficiency floor (1) + p21_selfsuff_region(h) Superregions eligible for the self-sufficiency floor (1=fully selected via policy_countries21) (1) + i21_min_selfsuff(t_all,h,k_trade) Minimum self-sufficiency ratio floor applied to forcesuff21 commodities (1) i21_trade_bal_reduction(t_all,h,k_trade) Trade balance reduction (1) i21_exp_shr(t_all,h,k_trade) Trade export shr (1) i21_trade_margin(h,k_trade) Trade margins (USD17MER per tDM) @@ -30,6 +31,7 @@ equations q21_notrade(h,k_notrade) Superregional production constraint of non-tradable commodities (mio. tDM per yr) q21_trade_reg(h,k_trade) Superregional trade balances i.e. minimum self-sufficiency ratio (1) q21_trade_reg_up(h,k_trade) Superregional trade balances i.e. maximum self-sufficiency ratio (1) + q21_min_selfsuff(h,k_trade) Superregional minimum self-sufficiency floor (mio. tDM per yr) q21_excess_dem(k_trade) Global excess demand (mio. tDM per yr) q21_excess_supply(h,k_trade) Superregional excess production (mio. tDM per yr) q21_cost_trade_tariff(h) Superregional tariff costs (mio. USD17MER per yr) @@ -49,6 +51,7 @@ parameters oq21_notrade(t,h,k_notrade,type) Superregional production constraint of non-tradable commodities (mio. tDM per yr) oq21_trade_reg(t,h,k_trade,type) Superregional trade balances i.e. minimum self-sufficiency ratio (1) oq21_trade_reg_up(t,h,k_trade,type) Superregional trade balances i.e. maximum self-sufficiency ratio (1) + oq21_min_selfsuff(t,h,k_trade,type) Superregional minimum self-sufficiency floor (mio. tDM per yr) oq21_excess_dem(t,k_trade,type) Global excess demand (mio. tDM per yr) oq21_excess_supply(t,h,k_trade,type) Superregional excess production (mio. tDM per yr) oq21_cost_trade_tariff(t,h,type) Superregional tariff costs (mio. USD17MER per yr) diff --git a/modules/21_trade/selfsuff_reduced/equations.gms b/modules/21_trade/selfsuff_reduced/equations.gms index cfb5f8f380..61d604f5c9 100644 --- a/modules/21_trade/selfsuff_reduced/equations.gms +++ b/modules/21_trade/selfsuff_reduced/equations.gms @@ -41,6 +41,17 @@ m21_baseline_production(vm_supply, v21_excess_prod, f21_self_suff) / sum(ct,i21_trade_bal_reduction(ct,h2,k_trade)); +*' Optional minimum self-sufficiency floor: for the commodities in `forcesuff21` and +*' the regions selected via `policy_countries21`, superregional production must cover +*' at least `i21_min_selfsuff` (= `s21_forcesuff_value` x the 2025 baseline +*' self-sufficiency) times superregional demand -- a one-sided lower bound holding each +*' commodity's 2025 trade intensity. Inactive (`i21_min_selfsuff` = 0) leaves develop +*' behaviour unchanged. + + q21_min_selfsuff(h2,k_trade)$(sum(ct,i21_min_selfsuff(ct,h2,k_trade)) > 0).. + sum(supreg(h2,i2),vm_prod_reg(i2,k_trade)) =g= + sum(ct,i21_min_selfsuff(ct,h2,k_trade)) * sum(supreg(h2,i2),vm_supply(i2,k_trade)); + *' The global excess demand of each tradable good `v21_excess_demad` equals to *' the sum over all the imports of importing superregions. diff --git a/modules/21_trade/selfsuff_reduced/input.gms b/modules/21_trade/selfsuff_reduced/input.gms index 0859350154..3de3938377 100644 --- a/modules/21_trade/selfsuff_reduced/input.gms +++ b/modules/21_trade/selfsuff_reduced/input.gms @@ -12,7 +12,10 @@ sets k_import21(k_trade) Commodities that can have additional imports to maintain feasibility / wood, woodfuel / - policy_countries21(iso) countries whose (fully selected) region is forced to wood and woodfuel self-sufficiency + forcesuff21(k_trade) Commodities forced to a minimum self-sufficiency floor for the (fully selected) regions in policy_countries21 (empty by default) + / / + + policy_countries21(iso) ISO codes of the region(s) subject to the self-sufficiency floor (like policy_countries56) / ABW,AFG,AGO,AIA,ALA,ALB,AND,ARE,ARG,ARM, ASM,ATA,ATF,ATG,AUS,AUT,AZE,BDI,BEL,BEN, BES,BFA,BGD,BGR,BHR,BHS,BIH,BLM,BLR,BLZ, @@ -44,7 +47,8 @@ scalars s21_trade_tariff Trade tariff switch (1=on 0=off) (1) / 1 / s21_cost_import Cost for additional imports to maintain feasibility (USD17MER per tDM) / 1500 / s21_min_trade_margin_forestry Minimum trade margin for forestry products (USD17MER per tDM) / 62 / - s21_force_wood_selfsuff Force full wood and woodfuel self-sufficiency for the regions selected via policy_countries21 (1=on 0=off) (1) / 0 / + s21_force_selfsuff Force a minimum self-sufficiency floor (s21_forcesuff_value) on the forcesuff21 commodities for the regions selected via policy_countries21 (1=on 0=off) (1) / 0 / + s21_forcesuff_value Fraction of the 2025 baseline self-sufficiency (f21_self_suff) held as a floor when s21_force_selfsuff=1 (1=freeze exports and imports at their 2025 intensity) (1) / 1 / ; table f21_trade_bal_reduction(t_all,trade_groups21,trade_regime21) Share of inelastic trade pool (1) diff --git a/modules/21_trade/selfsuff_reduced/postsolve.gms b/modules/21_trade/selfsuff_reduced/postsolve.gms index a788749156..9cfee81800 100644 --- a/modules/21_trade/selfsuff_reduced/postsolve.gms +++ b/modules/21_trade/selfsuff_reduced/postsolve.gms @@ -16,6 +16,7 @@ oq21_notrade(t,h,k_notrade,"marginal") = q21_notrade.m(h,k_notrade); oq21_trade_reg(t,h,k_trade,"marginal") = q21_trade_reg.m(h,k_trade); oq21_trade_reg_up(t,h,k_trade,"marginal") = q21_trade_reg_up.m(h,k_trade); + oq21_min_selfsuff(t,h,k_trade,"marginal") = q21_min_selfsuff.m(h,k_trade); oq21_excess_dem(t,k_trade,"marginal") = q21_excess_dem.m(k_trade); oq21_excess_supply(t,h,k_trade,"marginal") = q21_excess_supply.m(h,k_trade); oq21_cost_trade_tariff(t,h,"marginal") = q21_cost_trade_tariff.m(h); @@ -31,6 +32,7 @@ oq21_notrade(t,h,k_notrade,"level") = q21_notrade.l(h,k_notrade); oq21_trade_reg(t,h,k_trade,"level") = q21_trade_reg.l(h,k_trade); oq21_trade_reg_up(t,h,k_trade,"level") = q21_trade_reg_up.l(h,k_trade); + oq21_min_selfsuff(t,h,k_trade,"level") = q21_min_selfsuff.l(h,k_trade); oq21_excess_dem(t,k_trade,"level") = q21_excess_dem.l(k_trade); oq21_excess_supply(t,h,k_trade,"level") = q21_excess_supply.l(h,k_trade); oq21_cost_trade_tariff(t,h,"level") = q21_cost_trade_tariff.l(h); @@ -46,6 +48,7 @@ oq21_notrade(t,h,k_notrade,"upper") = q21_notrade.up(h,k_notrade); oq21_trade_reg(t,h,k_trade,"upper") = q21_trade_reg.up(h,k_trade); oq21_trade_reg_up(t,h,k_trade,"upper") = q21_trade_reg_up.up(h,k_trade); + oq21_min_selfsuff(t,h,k_trade,"upper") = q21_min_selfsuff.up(h,k_trade); oq21_excess_dem(t,k_trade,"upper") = q21_excess_dem.up(k_trade); oq21_excess_supply(t,h,k_trade,"upper") = q21_excess_supply.up(h,k_trade); oq21_cost_trade_tariff(t,h,"upper") = q21_cost_trade_tariff.up(h); @@ -61,6 +64,7 @@ oq21_notrade(t,h,k_notrade,"lower") = q21_notrade.lo(h,k_notrade); oq21_trade_reg(t,h,k_trade,"lower") = q21_trade_reg.lo(h,k_trade); oq21_trade_reg_up(t,h,k_trade,"lower") = q21_trade_reg_up.lo(h,k_trade); + oq21_min_selfsuff(t,h,k_trade,"lower") = q21_min_selfsuff.lo(h,k_trade); oq21_excess_dem(t,k_trade,"lower") = q21_excess_dem.lo(k_trade); oq21_excess_supply(t,h,k_trade,"lower") = q21_excess_supply.lo(h,k_trade); oq21_cost_trade_tariff(t,h,"lower") = q21_cost_trade_tariff.lo(h); diff --git a/modules/21_trade/selfsuff_reduced/preloop.gms b/modules/21_trade/selfsuff_reduced/preloop.gms index 0e60460af8..8af77c597b 100644 --- a/modules/21_trade/selfsuff_reduced/preloop.gms +++ b/modules/21_trade/selfsuff_reduced/preloop.gms @@ -18,21 +18,25 @@ i21_trade_bal_reduction(t_all,h,k_hardtrade21)=f21_trade_bal_reduction(t_all,"ha ); ); -*' Optionally force full wood & woodfuel self-sufficiency for the regions selected -*' via policy_countries21, to suppress wood-harvest leakage when those regions' -*' land-use emissions are constrained. s21_force_wood_selfsuff = 1 pins -*' the selected regions' wood/woodfuel production band to baseline demand (trade -*' balance reduction = 1) from sm_fix_SSP2 onwards; = 0 reproduces unchanged develop -*' behaviour. A region is forced only if ALL its countries are in policy_countries21 -*' (forcing self-sufficiency on a partial superregion is not meaningful), mirroring -*' the region mask in module 56. A superregion h is forced only if every country in -*' every region it contains (supreg(h,i), i_to_iso(i,iso)) is in policy_countries21; -*' empty / no fully-selected superregion makes it a no-op. +*' Region mask for the optional self-sufficiency floor (below): a superregion h is +*' eligible only if ALL its countries are in policy_countries21 (forcing self-sufficiency +*' on a partial superregion is not meaningful) -- i.e. every country in every region it +*' contains (supreg(h,i), i_to_iso(i,iso)) is selected; an empty / partially-selected +*' superregion makes it a no-op. Mirrors the region mask in module 56. p21_country_switch(iso) = 0; p21_country_switch(policy_countries21) = 1; p21_selfsuff_region(h) = 1$(sum((supreg(h,i), i_to_iso(i,iso)), 1 - p21_country_switch(iso)) = 0); -i21_trade_bal_reduction(t_all,h,"wood")$(s21_force_wood_selfsuff = 1 AND p21_selfsuff_region(h) AND m_year(t_all) > sm_fix_SSP2) = 1; -i21_trade_bal_reduction(t_all,h,"woodfuel")$(s21_force_wood_selfsuff = 1 AND p21_selfsuff_region(h) AND m_year(t_all) > sm_fix_SSP2) = 1; + +*' Optional minimum self-sufficiency floor: for the commodities in forcesuff21 (empty by +*' default) and the fully-selected regions in policy_countries21, hold self-sufficiency at +*' (s21_forcesuff_value x) its 2025 baseline level from sm_fix_SSP2 onwards, enforced by +*' q21_min_selfsuff. The floor tracks the input f21_self_suff (constant over time), so it +*' holds each commodity's 2025 export/import intensity. This subsumes the former wood-only +*' switch: to force wood/woodfuel self-sufficiency simply include them in forcesuff21. +*' s21_forcesuff_value = 1 freezes exactly at 2025; < 1 allows some erosion. Empty +*' forcesuff21 / s21_force_selfsuff = 0 keeps develop behaviour unchanged. +i21_min_selfsuff(t_all,h,k_trade) = 0; +i21_min_selfsuff(t_all,h,forcesuff21)$(s21_force_selfsuff = 1 AND p21_selfsuff_region(h) AND m_year(t_all) > sm_fix_SSP2) = s21_forcesuff_value * f21_self_suff(t_all,h,forcesuff21); i21_exports(t_all,h,k_trade) = ((f21_self_suff(t_all,h,k_trade) * f21_dom_supply(t_all,h,k_trade)) - f21_dom_supply(t_all,h,k_trade))$(f21_self_suff(t_all,h,k_trade) > 1); i21_exp_glo(t_all,k_trade) = sum(h, i21_exports(t_all,h,k_trade)); diff --git a/scripts/start/nzb_hpc_grid.R b/scripts/start/nzb_hpc_grid.R index cf28c6d70b..d836a6f87d 100644 --- a/scripts/start/nzb_hpc_grid.R +++ b/scripts/start/nzb_hpc_grid.R @@ -57,7 +57,8 @@ cfg$gms$ghg_policy <- "cap_apr26_reg" # AR6 GWP baked in (preloop.gm cfg$gms$c56_cap_policy <- "all" # soil incl. (PR #904) cfg$gms$s56_source_bounds_on <- 0 cfg$gms$policy_countries56 <- "BRA" -cfg$gms$s21_force_wood_selfsuff <- 1 # forced BRA wood self-sufficiency (no leakage) +cfg$gms$s21_force_selfsuff <- 1 # wood self-suff via the general floor (former s21_force_wood_selfsuff) +cfg$gms$forcesuff21 <- "wood, woodfuel" cfg$gms$policy_countries21 <- "BRA" cfg$gms$c32_aff_policy <- "npi"; cfg$gms$c35_ad_policy <- "npi"; cfg$gms$c35_aolc_policy <- "npi" cfg$gms$c_timesteps <- "5year2050" # <-- HORIZON knob: "coup2100" for 2100 From 360786e3862a901332c914a66573b87cfc5052e5 Mon Sep 17 00:00:00 2001 From: florianh Date: Thu, 2 Jul 2026 21:32:11 +0200 Subject: [PATCH 7/8] nzb: export-protection HPC grid start script scripts/start/nzb_export_grid.R -- one start script for the 61-run NZB export grid (each start_run -> one SLURM job). 7 families, indexed by achieved reported GWP100AR6|Land BRA AFOLU 2050: gC_wdpa / gC_30by30 / gC_half : conservation, cap alone + forced 1.5C MACC gA_RoW2C : RoW at 2C, BRA capped/unpriced (WDPA), baseline BRA bioenergy gB_price : cap + BRA 1.5C CO2 price (price-driven A/R + MACC), WDPA gF_freeze: gC_wdpa + forcesuff21 = all BRA f21_self_suff>1 (export freeze) g0_npi : NPI-only anchor All: cap_apr26_reg, nocc, AR6 GWP, c56_cap_policy=all, s21_force_selfsuff=1 (BRA), forest NPI, 5year2050. Reported ladder {-1000,-500,-250,-100,-50,0,50,100,250,500} (cap target = reported + 50 nominal; dashboard re-indexes on achieved). BRA price trimmed to its <= -63 window. NZB_FAMILIES env for subset re-runs. --- scripts/start/nzb_export_grid.R | 169 ++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 scripts/start/nzb_export_grid.R diff --git a/scripts/start/nzb_export_grid.R b/scripts/start/nzb_export_grid.R new file mode 100644 index 0000000000..19b7317f2b --- /dev/null +++ b/scripts/start/nzb_export_grid.R @@ -0,0 +1,169 @@ +## nzb_export_grid.R ============================================================ +## NZB export-protection grid for the PIK HPC (SLURM). One start script; each +## start_run() -> one SLURM job. Launch on the LOGIN node with submit=direct. +## +## PREREQUISITE (once, on login, to warm the input cache / avoid the H12-fallback): +## Rscript scripts/start/download_data_BRA.R +## then verify core/sets.gms shows `Regionscode: 5638d5dc` + 13 regions (incl. BRA). +## +## Launch: Rscript start.R runscripts=nzb_export_grid submit=direct +## subset: NZB_FAMILIES=F Rscript start.R runscripts=nzb_export_grid submit=direct +## +## FAMILIES (7; all: cap_apr26_reg, nocc, AR6 GWP, c56_cap_policy=all, BRA cap, +## s21_force_selfsuff=1 (BRA), WDPA base conservation, forest NPI, 5year2050; +## indexed by ACHIEVED reported GWP100AR6|Land BRA AFOLU 2050): +## gC_wdpa / gC_30by30 / gC_half : conservation, cap ALONE + forced 1.5C MACC. +## gA_RoW2C : RoW pursues 2C (PkBudg1000 + price-induced A/R + 2C 2nd-gen bioenergy); +## BRA capped, unpriced, WDPA, BRA bioenergy held at baseline (MACRO in NZB). +## gB_price : cap + BRA 1.5C CO2 price (PkBudg650) -> price-driven A/R + MACC; WDPA. +## gF_freeze: like gC_wdpa but forcesuff21 = ALL BRA f21_self_suff>1 (export freeze). +## g0_npi : NPI only (no cap/MACC/price) anchor ("do nothing"). +## +## LADDER (reported targets, Mt): {-1000,-500,-250,-100,-50,0,50,100,250,500}; the cap +## target = reported + CAPOFFSET (nominal; the true offset is ~+30..+70, varying with +## family/depth, so the dashboard re-indexes on ACHIEVED reported). B is trimmed to its +## sub-floor {-1000,-500,-250,-100} (its 0..+500 half is non-binding, floors ~-63). +## Reachability: +250/+500 saturate at each family's no-cap plateau; -500/-1000 sit at/ +## below the feasibility frontier (may run on slack). Both are informative endpoints. +## +## RUN COUNT: C(3x11) + A(11) + F(11) + B(5) + anchor(1) = 61 jobs. +## ============================================================================ +FAMILIES <- strsplit(Sys.getenv("NZB_FAMILIES", "C,A,B,F,0"), ",")[[1]] + +library(lucode2); library(gms); library(magpie4) +source("config/default.cfg"); source("scripts/start_functions.R") + +# ---- input + infra (BRA-H13 W3; on HPC download_distribute falls back to local mirrors) ---- +cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", + cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", + validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", + additional = "additional_data_rev4.65.tgz", + calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") +cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), + getOption("magpie_repos")) +cfg$force_download <- FALSE; cfg$force_replace <- TRUE +cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE +cfg <- setScenario(cfg, "nocc") + +# ---- common GHG-policy / trade / horizon (all runs) -------------------------------- +cfg$gms$ghg_policy <- "cap_apr26_reg" # AR6 GWP baked in (preloop.gms:131-133) +cfg$gms$c56_cap_policy <- "all" # soil incl. (PR #904) +cfg$gms$s56_source_bounds_on <- 0 +cfg$gms$policy_countries56 <- "BRA" +cfg$gms$s21_force_selfsuff <- 1 # min self-sufficiency floor (general mechanism) +cfg$gms$forcesuff21 <- "wood, woodfuel" # default (overridden for gF_freeze) +cfg$gms$policy_countries21 <- "BRA" +cfg$gms$c32_aff_policy <- "npi"; cfg$gms$c35_ad_policy <- "npi"; cfg$gms$c35_aolc_policy <- "npi" +cfg$gms$c_timesteps <- "5year2050" # <-- HORIZON knob: "coup2100" for 2100 +cfg$output <- c("rds_report") +cfg$results_folder <- "output/:title:" # undated folders -> stable names +cfg$sequential <- FALSE +cfg$qos <- "standby" # many runs > priority MaxJobsPU cap + +CAPOFFSET <- 50 # nominal reported->cap offset +reps_main <- c(-1000, -500, -250, -100, -50, 0, 50, 100, 250, 500) # C, A, F +reps_B <- c(-1000, -500, -250, -100) # B trimmed (<= -63 floor) + +# all BRA commodities with f21_self_suff > 1 (net exporters) + wood/woodfuel (gF_freeze) +FREEZE_LIST <- paste("wood, woodfuel, fibres, soybean, groundnut, sugar, oilcakes,", + "livst_pig, maiz, livst_chick, others, livst_rum, alcohol, oils,", + "rice_pro, livst_milk, cottn_pro, brans, cassav_sp, livst_egg") + +reptag <- function(r) if (r == 0) "rep000" else sprintf("rep%s%d", if (r < 0) "M" else "P", abs(r)) +launch <- function(cfg, title) { cfg$title <- title; start_run(cfg, codeCheck = FALSE) } + +# ---- lever helpers ----------------------------------------------------------------- +macc_forced <- function(cfg) { # forced 1.5C MACC, faded 2025->2050 + for (s in c("n_soil","n_awms","ch4_rice","ch4_entferm","ch4_awms")) + cfg$gms[[paste0("s57_maxmac_", s)]] <- 106 + cfg$gms$s57_maxmac_fadein <- 1 + cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 + cfg +} +macc_pricedriven <- function(cfg) { # abatement follows the CO2 price + for (s in c("n_soil","n_awms","ch4_rice","ch4_entferm","ch4_awms")) + cfg$gms[[paste0("s57_maxmac_", s)]] <- -1 + cfg$gms$s57_maxmac_fadein <- 0 + cfg +} +conservation <- function(cfg, scen) { # "none"(=WDPA base) / "30by30" / "PBL_HalfEarth" + cfg$gms$c22_protect_scenario <- scen + cfg$gms$c22_protect_scenario_noselect <- "none" + cfg$gms$s22_restore_land <- if (scen == "none") 0 else 1 + cfg$gms$policy_countries22 <- "BRA" + cfg +} +set_cap <- function(cfg, reported) { + cfg$gms$s56_emis_cap_parametric <- 1 + cfg$gms$s56_emis_cap_start_year <- 2035 + cfg$gms$s56_emis_cap_start_value <- 600 + cfg$gms$s56_emis_cap_target_year <- 2050 + cfg$gms$s56_emis_cap_target <- reported + CAPOFFSET + cfg +} +set_nocap <- function(cfg) { + cfg$gms$s56_emis_cap_parametric <- 0; cfg$gms$c56_emis_cap_scenario <- "none"; cfg +} +ladder <- function(base, fam, reps) { # ref (no-cap) + cap ladder + launch(set_nocap(base), sprintf("nzb_%s_ref", fam)) + for (r in reps) launch(set_cap(base, r), sprintf("nzb_%s_%s", fam, reptag(r))) +} + +# ============================ Family C: conservation (cap alone) ==================== +if ("C" %in% FAMILIES) for (cons in list(list(tag="wdpa", scen="none"), + list(tag="30by30", scen="30by30"), + list(tag="half", scen="PBL_HalfEarth"))) { + base <- conservation(macc_forced(cfg), cons$scen) + base$gms$c56_pollutant_prices <- "none" + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" + base$gms$s56_c_price_induced_aff <- 0 + ladder(base, sprintf("gC_%s", cons$tag), reps_main) +} + +# ===================== Family A: RoW pursues 2C, BRA capped (WDPA, BRA bioen baseline) ===== +if ("A" %in% FAMILIES) { + base <- conservation(macc_forced(cfg), "none") # WDPA (was HalfEarth) + base$gms$c56_pollutant_prices <- "none" # BRA capped, not priced + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C price + base$gms$s56_c_price_induced_aff <- 1 # price-induced A/R (RoW only) + base$gms$scen_countries60 <- "BRA" # split BRA vs RoW bioenergy + base$gms$c60_2ndgen_biodem <- "R34M410-SSP2-NPi2025" # BRA baseline (MACRO in NZB) + base$gms$c60_2ndgen_biodem_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C bioenergy demand + ladder(base, "gA_RoW2C", reps_main) +} + +# ===================== Family B: cap + BRA 1.5C price (drives A/R + MACC), WDPA ====== +if ("B" %in% FAMILIES) { + base <- conservation(macc_pricedriven(cfg), "none") # WDPA (was HalfEarth) + base$gms$c56_pollutant_prices <- "R34M410-SSP2-PkBudg650" # BRA priced 1.5C + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" # RoW current policies + base$gms$s56_c_price_induced_aff <- 1 # price-induced A/R (BRA) + ladder(base, "gB_price", reps_B) # trimmed to <= -63 +} + +# ===================== Family F: export freeze (gC_wdpa + all f21>1 forcesuff21) ===== +if ("F" %in% FAMILIES) { + base <- conservation(macc_forced(cfg), "none") # WDPA + base$gms$c56_pollutant_prices <- "none" + base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" + base$gms$s56_c_price_induced_aff <- 0 + base$gms$forcesuff21 <- FREEZE_LIST # freeze ALL BRA exports + ladder(base, "gF_freeze", reps_main) +} + +# ===================== Anchor: NPI only (no MACC / restore / price / cap) ============ +if ("0" %in% FAMILIES) { + anchor <- set_nocap(conservation(macc_pricedriven(cfg), "none")) + anchor$gms$c56_pollutant_prices <- "none" + anchor$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" + anchor$gms$s56_c_price_induced_aff <- 0 + launch(anchor, "nzb_g0_npi") +} + +nC <- if ("C" %in% FAMILIES) 3 * (length(reps_main) + 1) else 0 +nA <- if ("A" %in% FAMILIES) length(reps_main) + 1 else 0 +nB <- if ("B" %in% FAMILIES) length(reps_B) + 1 else 0 +nF <- if ("F" %in% FAMILIES) length(reps_main) + 1 else 0 +n0 <- if ("0" %in% FAMILIES) 1 else 0 +cat(sprintf("== nzb_export_grid launched [%s]: C(%d)+A(%d)+B(%d)+F(%d)+anchor(%d) = %d jobs ==\n", + paste(FAMILIES, collapse=","), nC, nA, nB, nF, n0, nC + nA + nB + nF + n0)) From 6bb703dff71e4954e135daea4822670b004ce672 Mon Sep 17 00:00:00 2001 From: florianh Date: Fri, 3 Jul 2026 09:46:53 +0200 Subject: [PATCH 8/8] nzb export grid: single portable start script + sugar-crop self-sufficiency Consolidate the NZB start scripts to one portable example (scripts/start/nzb_export_grid.R) and remove the exploratory ones; strip HPC/SLURM/site-specific wording from the keeper so it runs anywhere. Add cane/cassava/molasses to the common forcesuff21 self-sufficiency floor so no run shows spurious raw-sugar imports (a processing-hub artifact at f21~1.0). --- scripts/start/nzb_R0_npi_cpriceAR.R | 68 ---------- scripts/start/nzb_R0_npi_fullmacc_rest.R | 54 -------- scripts/start/nzb_R0_ref.R | 87 ------------ scripts/start/nzb_baseline_variants.R | 74 ----------- scripts/start/nzb_cap_extend_onon.R | 70 ---------- scripts/start/nzb_export_grid.R | 34 ++--- scripts/start/nzb_hpc_grid.R | 160 ----------------------- scripts/start/nzb_nocap_corners.R | 63 --------- 8 files changed, 17 insertions(+), 593 deletions(-) delete mode 100644 scripts/start/nzb_R0_npi_cpriceAR.R delete mode 100644 scripts/start/nzb_R0_npi_fullmacc_rest.R delete mode 100644 scripts/start/nzb_R0_ref.R delete mode 100644 scripts/start/nzb_baseline_variants.R delete mode 100644 scripts/start/nzb_cap_extend_onon.R delete mode 100644 scripts/start/nzb_hpc_grid.R delete mode 100644 scripts/start/nzb_nocap_corners.R diff --git a/scripts/start/nzb_R0_npi_cpriceAR.R b/scripts/start/nzb_R0_npi_cpriceAR.R deleted file mode 100644 index 59c2ab6d56..0000000000 --- a/scripts/start/nzb_R0_npi_cpriceAR.R +++ /dev/null @@ -1,68 +0,0 @@ -## nzb_R0_npi_cpriceAR.R -------------------------------------------------------- -## New no-cap reference: NPI forest + a 1.5C CO2 PRICE (BRA) that drives BOTH the -## non-CO2 MACCs AND carbon-price-induced afforestation/reforestation (A/R), with -## Half-Earth restoration OFF. Purpose: test whether price-driven A/R can deliver -## a deeper BRA land-CO2 sink by 2050 than the forced Half-Earth restoration. -## -## Mechanism (verified in cap_apr26_reg + module 57): -## - c56_pollutant_prices = R34M410-SSP2-PkBudg650 -> 1.5C price (~641 USD/tCO2eq -## by 2050; the same level as MACC step 106). Applied to BRA only via -## policy_countries56="BRA"; rest of world stays at NPi2025 (noselect). Price is -## muted until 2030 (c56_mute_ghgprices_until) then follows the PkBudg650 path. -## - s57_maxmac_* = -1 -> MACC abatement is PRICE-DRIVEN (forced override off). -## - s56_c_price_induced_aff = 1 -> the CO2 price rewards A/R (faded in from 2030). -## - restoration off: c22_protect_scenario=none, s22_restore_land=0 (WDPA base only). -## - no cap, nocc, NPI forest policy. -## --------------------------------------------------------------------------- -library(lucode2); library(gms); library(magpie4) -source("config/default.cfg"); source("scripts/start_functions.R") - -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) -cfg$force_download <- FALSE; cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE -cfg <- setScenario(cfg, "nocc") - -cfg$gms$ghg_policy <- "cap_apr26_reg" -cfg$gms$c56_cap_policy <- "all" -cfg$gms$c56_emis_cap_scenario <- "none" # NO cap -cfg$gms$s56_emis_cap_parametric <- 0 -cfg$gms$s56_source_bounds_on <- 0 - -# --- 1.5C CO2 price for BRA (drives MACC + A/R); rest of world at NPi baseline --- -cfg$gms$c56_pollutant_prices <- "R34M410-SSP2-PkBudg650" -cfg$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" -cfg$gms$policy_countries56 <- "BRA" -# carbon-price-induced afforestation ON (faded in from 2030) -cfg$gms$s56_c_price_induced_aff <- 1 - -# --- price-driven MACC (forced override OFF) --- -cfg$gms$s57_maxmac_n_soil <- -1 -cfg$gms$s57_maxmac_n_awms <- -1 -cfg$gms$s57_maxmac_ch4_rice <- -1 -cfg$gms$s57_maxmac_ch4_entferm <- -1 -cfg$gms$s57_maxmac_ch4_awms <- -1 -cfg$gms$s57_maxmac_fadein <- 0 - -# --- NPI forest policy --- -cfg$gms$c32_aff_policy <- "npi" -cfg$gms$c35_ad_policy <- "npi" -cfg$gms$c35_aolc_policy <- "npi" - -# --- restoration OFF (WDPA base protection only) --- -cfg$gms$c22_protect_scenario <- "none" -cfg$gms$c22_protect_scenario_noselect <- "none" -cfg$gms$policy_countries22 <- "BRA" -cfg$gms$s22_restore_land <- 0 - -cfg$gms$c_timesteps <- "5year2050" -cfg$output <- c("rds_report") -cfg$sequential <- FALSE - -cfg$title <- "nzb_R0_npi_cpriceAR" -start_run(cfg, codeCheck = FALSE) diff --git a/scripts/start/nzb_R0_npi_fullmacc_rest.R b/scripts/start/nzb_R0_npi_fullmacc_rest.R deleted file mode 100644 index c993ed2b74..0000000000 --- a/scripts/start/nzb_R0_npi_fullmacc_rest.R +++ /dev/null @@ -1,54 +0,0 @@ -## nzb_R0_npi_fullmacc_rest.R --------------------------------------------------- -## Corrected baseline variant: NPI forest policy + FULL MACC potential (step 201) -## + restoration ON (Half-Earth PBL, BRA). No cap. (Replaces the mistaken -## nzb_R0_npi_fullmacc which had restore OFF.) -## Same baseline frame as the other variants: nocc, non-binding cap, no GHG prices. -## --------------------------------------------------------------------------- -library(lucode2); library(gms); library(magpie4) -source("config/default.cfg"); source("scripts/start_functions.R") - -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) -cfg$force_download <- FALSE; cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE -cfg <- setScenario(cfg, "nocc") - -cfg$gms$ghg_policy <- "cap_apr26_reg" -cfg$gms$c56_cap_policy <- "all" -cfg$gms$c56_emis_cap_scenario <- "none" # non-binding (no cap) -cfg$gms$s56_emis_cap_parametric <- 0 -cfg$gms$s56_source_bounds_on <- 0 -cfg$gms$c56_pollutant_prices <- "none" -cfg$gms$s56_c_price_induced_aff <- 0 -cfg$gms$c_timesteps <- "5year2050" -cfg$output <- c("rds_report") -cfg$sequential <- FALSE - -# forest policy = NPI (default, set explicitly) -cfg$gms$c32_aff_policy <- "npi" -cfg$gms$c35_ad_policy <- "npi" -cfg$gms$c35_aolc_policy <- "npi" - -# restoration ON (Half-Earth PBL, BRA) -cfg$gms$c22_protect_scenario <- "PBL_HalfEarth" -cfg$gms$c22_protect_scenario_noselect <- "none" -cfg$gms$policy_countries22 <- "BRA" -cfg$gms$s22_restore_land <- 1 - -# FULL MACC potential: max curve step 201 (~1222 USD/tCO2eq), phased in as usual -cfg$gms$s57_maxmac_n_soil <- 201 -cfg$gms$s57_maxmac_n_awms <- 201 -cfg$gms$s57_maxmac_ch4_rice <- 201 -cfg$gms$s57_maxmac_ch4_entferm <- 201 -cfg$gms$s57_maxmac_ch4_awms <- 201 -cfg$gms$s57_maxmac_fadein <- 1 -cfg$gms$s57_maxmac_fadein_start <- 2025 -cfg$gms$s57_maxmac_fadein_end <- 2050 - -cfg$title <- "nzb_R0_npi_fullmacc_rest" -start_run(cfg, codeCheck = FALSE) diff --git a/scripts/start/nzb_R0_ref.R b/scripts/start/nzb_R0_ref.R deleted file mode 100644 index 23e5bc76b6..0000000000 --- a/scripts/start/nzb_R0_ref.R +++ /dev/null @@ -1,87 +0,0 @@ -## nzb_R0_ref.R -------------------------------------------------------------- -## NZB R0 REFERENCE run (no binding cap). Locates where Brazil's reported AFOLU -## lands from the prescribed levers ALONE, before any cap binds. -## -## Revised design (call with Alex Koberle, 2026-06-25; recipe (a)): -## - NO climate-change impacts -> setScenario(cfg, "nocc") sets all 7 climate -## switches (c14 yields, c35 pot_forest, c42/c43 water, c52 carbon, -## c52 land_carbon_sink, c59 som). Pure bookkeeping convention. -## - NO GHG prices -> c56_pollutant_prices = "none" (im_pollutant_prices = 0), -## s56_c_price_induced_aff = 0. Reason: do not distort the deforestation signal. -## - A/R via restoration -> Half-Earth PBL conservation, BRA only, forced, -## phased 2025->2050 (the knob that will later vary with the cap). -## - Non-CO2 via FIXED 1.5C MACC fade -> s57_maxmac_* = 106 (= PkBudg650 2050 -## step: co2_c 2350 USD/tC ~ 641 USD/tCO2eq; step = ceil(2350/22.4)+1 = 106), -## phased linearly from step 1 @2025 to 106 @2050 (s57_maxmac_fadein = 1). -## All five non-CO2 sources. Global (BRA-only MACC is a later refinement). -## - Cap scope c56_cap_policy = "all" (soil now included; PR #904 applied). -## - Cap level c56_emis_cap_scenario = "none" -> p56_emis_cap = 1e6 = NON-BINDING. -## -## Soil-carbon bugfix PR #904 already applied to modules/59_som/{cellpool_jan23, -## static_jan19}/postsolve.gms. MACC linear fade-in added to -## modules/57_maccs/on_aug22/{input,declarations,preloop}.gms (gated by -## s57_maxmac_fadein; fadein=0 reproduces the flat baseline bit-for-bit). -## -## Run directly from this worktree (project folder renamed AlexKoberle, ASCII path -## -> renv no longer breaks; the separate magpie_nzb_run copy was retired). Input -## rev4.131 W3 already prepared in input/ (source_files.log matches) -> no download. -## --------------------------------------------------------------------------- - -library(lucode2) # setScenario lives in gms/lucode2 - load before use -library(gms) -library(magpie4) -source("config/default.cfg") -source("scripts/start_functions.R") - -# --- input data (rev4.131 W3, == Alex's runs) ------------------------------- -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) - -# --- do NOT download / recalibrate (proven config from prior runs) ---------- -cfg$force_download <- FALSE -cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE -cfg$recalibrate_landconversion_cost <- FALSE - -# --- climate OFF: bookkeeping convention (all 7 switches) ------------------- -cfg <- setScenario(cfg, "nocc") - -# --- run settings ----------------------------------------------------------- -cfg$title <- "nzb_R0_ref" -cfg$gms$ghg_policy <- "cap_apr26_reg" - -# cap: scope "all" (soil included; bug fixed); NON-BINDING (R0 reference) -cfg$gms$c56_cap_policy <- "all" -cfg$gms$c56_emis_cap_scenario <- "none" # p56_emis_cap = 1e6 -> never binds -cfg$gms$s56_source_bounds_on <- 0 - -# NO GHG prices (do not distort deforestation); no C-price-induced A/R -cfg$gms$c56_pollutant_prices <- "none" -cfg$gms$s56_c_price_induced_aff <- 0 - -# A/R via Half-Earth restoration, Brazil only (forced, phased 2025->2050) -cfg$gms$c22_protect_scenario <- "PBL_HalfEarth" -cfg$gms$c22_protect_scenario_noselect <- "none" -cfg$gms$policy_countries22 <- "BRA" -cfg$gms$s22_restore_land <- 1 - -# Non-CO2 via FIXED 1.5C MACC fade (step 1 @2025 -> 106 @2050, linear, 5 sources) -cfg$gms$s57_maxmac_fadein <- 1 -cfg$gms$s57_maxmac_fadein_start <- 2025 -cfg$gms$s57_maxmac_fadein_end <- 2050 -cfg$gms$s57_maxmac_n_soil <- 106 -cfg$gms$s57_maxmac_n_awms <- 106 -cfg$gms$s57_maxmac_ch4_rice <- 106 -cfg$gms$s57_maxmac_ch4_entferm <- 106 -cfg$gms$s57_maxmac_ch4_awms <- 106 - -cfg$gms$c_timesteps <- "5year2050" -cfg$output <- c("rds_report") -cfg$sequential <- FALSE - -start_run(cfg, codeCheck = FALSE) diff --git a/scripts/start/nzb_baseline_variants.R b/scripts/start/nzb_baseline_variants.R deleted file mode 100644 index 2e20e23ace..0000000000 --- a/scripts/start/nzb_baseline_variants.R +++ /dev/null @@ -1,74 +0,0 @@ -## nzb_baseline_variants.R ------------------------------------------------------ -## Baseline (no-cap) sensitivities to complete the reference picture. All share -## the {off,off}-style baseline (no cap, restore off, WDPA base only, nocc, no GHG -## prices); they differ only in forest-policy stringency and MACC ceiling. -## -## 1. nzb_R0_offoff_polnone forest policy = none (no NPI) MACC off -## 2. nzb_R0_offoff_ndc forest policy = ndc MACC off -## 3. nzb_R0_npi_fullmacc forest = npi + FULL MACC (201) MACC full -## -## Forest policy = c32_aff_policy (afforestation) + c35_ad_policy (avoided defor) -## + c35_aolc_policy (avoided other-land conversion). -## "Full MACC potential" = s57_maxmac_* = 201 (max curve step ~1222 USD/tCO2eq) -## vs the library's 106 (~641 USD, the 1.5C price). fadein=1 kept (same phase-in). -## The NPI {off,off} no-cap baseline already exists (nzb_R0_mOFF_rOFF). -## All 3 fit one wave (<=6 on 24 GB). Output: rds_report. -## --------------------------------------------------------------------------- -library(lucode2); library(gms); library(magpie4) -source("config/default.cfg"); source("scripts/start_functions.R") - -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) -cfg$force_download <- FALSE; cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE -cfg <- setScenario(cfg, "nocc") - -# ---- common baseline config (no cap, restore off, no prices) --------------- -cfg$gms$ghg_policy <- "cap_apr26_reg" -cfg$gms$c56_cap_policy <- "all" -cfg$gms$c56_emis_cap_scenario <- "none" # non-binding (no cap) -cfg$gms$s56_emis_cap_parametric <- 0 # force OFF (input.gms drift guard) -cfg$gms$s56_source_bounds_on <- 0 -cfg$gms$c56_pollutant_prices <- "none" -cfg$gms$s56_c_price_induced_aff <- 0 -# restore off (baseline): WDPA base protection only -cfg$gms$c22_protect_scenario <- "none"; cfg$gms$s22_restore_land <- 0 -cfg$gms$c22_protect_scenario_noselect <- "none"; cfg$gms$policy_countries22 <- "BRA" -cfg$gms$c_timesteps <- "5year2050" -cfg$output <- c("rds_report") -cfg$sequential <- FALSE - -set_macc <- function(cfg, step){ # step (e.g. 106, 201) or -1 = off - cfg$gms$s57_maxmac_n_soil <- step; cfg$gms$s57_maxmac_n_awms <- step - cfg$gms$s57_maxmac_ch4_rice <- step; cfg$gms$s57_maxmac_ch4_entferm <- step - cfg$gms$s57_maxmac_ch4_awms <- step - cfg$gms$s57_maxmac_fadein <- if (step > 0) 1 else 0 - cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 - cfg -} -set_forest <- function(cfg, pol){ # "none" | "npi" | "ndc" - cfg$gms$c32_aff_policy <- pol - cfg$gms$c35_ad_policy <- pol - cfg$gms$c35_aolc_policy <- pol - cfg -} - -# variant | forest policy | macc step -variants <- list( - nzb_R0_offoff_polnone = list(forest = "none", macc = -1), - nzb_R0_offoff_ndc = list(forest = "ndc", macc = -1), - nzb_R0_npi_fullmacc = list(forest = "npi", macc = 201)) - -launch <- function(cfg, title, v){ - cfg <- set_forest(cfg, v$forest); cfg <- set_macc(cfg, v$macc) - cfg$title <- title - start_run(cfg, codeCheck = FALSE) - title -} -titles <- mapply(function(nm, v) launch(cfg, nm, v), names(variants), variants) -cat("== launched 3 baseline-variant runs ==\n"); print(unname(titles)) diff --git a/scripts/start/nzb_cap_extend_onon.R b/scripts/start/nzb_cap_extend_onon.R deleted file mode 100644 index 0b0cf7da65..0000000000 --- a/scripts/start/nzb_cap_extend_onon.R +++ /dev/null @@ -1,70 +0,0 @@ -## nzb_cap_extend_onon.R -------------------------------------------------------- -## Extend the {MACC on, restore on} cap ladder so the dashboard slider can span -## reported BRA AFOLU 2050 from ~-200 to ~+200 Mt. 4 NEW runs via the parametric -## switch (s56_emis_cap_parametric=1); no cs3 columns, no GAMS changes. -## -## capm200 600/400/200 -> -200 fixed ramp (matches existing grid; monotone) -## capm150 600/400/200 -> -150 fixed ramp -## cap200 600/467/333 -> +200 SCALED monotone waypoints (loose cap) -## cap300 600/500/400 -> +300 SCALED monotone waypoints -## -## Lower pair brackets reported -200; upper pair brackets reported +200 (reported -## ~ endpoint - ~50..77 offset; reported saturates at the no-cap ~277). Scaled -## waypoints = linear 600(2035) -> endpoint(2050) so the loose-cap path declines -## smoothly instead of dipping to 200 in 2045 then rebounding. -## All 4 fit one wave (<=6 on 24 GB). Output: rds_report. {on,on} levers only. -## --------------------------------------------------------------------------- -library(lucode2); library(gms); library(magpie4) -source("config/default.cfg"); source("scripts/start_functions.R") - -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) -cfg$force_download <- FALSE; cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE -cfg <- setScenario(cfg, "nocc") - -# ---- common cap config (== library) ---------------------------------------- -cfg$gms$ghg_policy <- "cap_apr26_reg" -cfg$gms$c56_cap_policy <- "all" -cfg$gms$s56_source_bounds_on <- 0 -cfg$gms$c56_pollutant_prices <- "none" -cfg$gms$s56_c_price_induced_aff <- 0 -cfg$gms$c_timesteps <- "5year2050" -cfg$output <- c("rds_report") -cfg$sequential <- FALSE - -# ---- {MACC on, restore on} levers (fixed across these 4 runs) -------------- -v <- 106 -cfg$gms$s57_maxmac_n_soil <- v; cfg$gms$s57_maxmac_n_awms <- v -cfg$gms$s57_maxmac_ch4_rice <- v; cfg$gms$s57_maxmac_ch4_entferm <- v -cfg$gms$s57_maxmac_ch4_awms <- v -cfg$gms$s57_maxmac_fadein <- 1 -cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 -cfg$gms$c22_protect_scenario <- "PBL_HalfEarth"; cfg$gms$s22_restore_land <- 1 -cfg$gms$c22_protect_scenario_noselect <- "none"; cfg$gms$policy_countries22 <- "BRA" - -# ---- parametric cap on; BRA-only via policy_countries56. The linear ramp from -# start_value (600 @ start_year) to the 2050 endpoint reproduces the scaled -# waypoints; only the endpoint differs per run. -cfg$gms$s56_emis_cap_parametric <- 1 -cfg$gms$s56_emis_cap_start_year <- 2035 -cfg$gms$s56_emis_cap_start_value <- 600 -cfg$gms$s56_emis_cap_target_year <- 2050 -cfg$gms$policy_countries56 <- "BRA" # parametric cap applies to this region only - -# capcol -> 2050 endpoint (Tg CO2eq/yr) -runs <- list(capm200 = -200, capm150 = -150, cap200 = 200, cap300 = 300) - -launch <- function(cfg, capcol, target){ - cfg$gms$s56_emis_cap_target <- target - cfg$title <- sprintf("nzb_lib_mON_rON_%s", capcol) - start_run(cfg, codeCheck = FALSE) - cfg$title -} -titles <- mapply(function(cc, t) launch(cfg, cc, t), names(runs), runs) -cat("== launched 4 extended {on,on} cap runs ==\n"); print(unname(titles)) diff --git a/scripts/start/nzb_export_grid.R b/scripts/start/nzb_export_grid.R index 19b7317f2b..690c274093 100644 --- a/scripts/start/nzb_export_grid.R +++ b/scripts/start/nzb_export_grid.R @@ -1,13 +1,13 @@ ## nzb_export_grid.R ============================================================ -## NZB export-protection grid for the PIK HPC (SLURM). One start script; each -## start_run() -> one SLURM job. Launch on the LOGIN node with submit=direct. +## NZB export-protection grid: one start script that launches the whole 61-run +## comparison (7 policy families x a reported-AFOLU cap ladder). Each start_run() +## submits one MAgPIE run. ## -## PREREQUISITE (once, on login, to warm the input cache / avoid the H12-fallback): -## Rscript scripts/start/download_data_BRA.R -## then verify core/sets.gms shows `Regionscode: 5638d5dc` + 13 regions (incl. BRA). +## PREREQUISITE: the BRA-H13 W3 input data (the tarballs listed under cfg$input +## below) must be available to start_run / download_distribute. ## -## Launch: Rscript start.R runscripts=nzb_export_grid submit=direct -## subset: NZB_FAMILIES=F Rscript start.R runscripts=nzb_export_grid submit=direct +## Launch: Rscript start.R runscripts=nzb_export_grid +## subset a family: NZB_FAMILIES=F Rscript start.R runscripts=nzb_export_grid ## ## FAMILIES (7; all: cap_apr26_reg, nocc, AR6 GWP, c56_cap_policy=all, BRA cap, ## s21_force_selfsuff=1 (BRA), WDPA base conservation, forest NPI, 5year2050; @@ -26,21 +26,19 @@ ## Reachability: +250/+500 saturate at each family's no-cap plateau; -500/-1000 sit at/ ## below the feasibility frontier (may run on slack). Both are informative endpoints. ## -## RUN COUNT: C(3x11) + A(11) + F(11) + B(5) + anchor(1) = 61 jobs. +## RUN COUNT: C(3x11) + A(11) + F(11) + B(5) + anchor(1) = 61 runs. ## ============================================================================ FAMILIES <- strsplit(Sys.getenv("NZB_FAMILIES", "C,A,B,F,0"), ",")[[1]] library(lucode2); library(gms); library(magpie4) source("config/default.cfg"); source("scripts/start_functions.R") -# ---- input + infra (BRA-H13 W3; on HPC download_distribute falls back to local mirrors) ---- +# ---- input (BRA-H13 W3) ------------------------------------------------------------ cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", additional = "additional_data_rev4.65.tgz", calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) cfg$force_download <- FALSE; cfg$force_replace <- TRUE cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE cfg <- setScenario(cfg, "nocc") @@ -51,23 +49,25 @@ cfg$gms$c56_cap_policy <- "all" # soil incl. (PR #904) cfg$gms$s56_source_bounds_on <- 0 cfg$gms$policy_countries56 <- "BRA" cfg$gms$s21_force_selfsuff <- 1 # min self-sufficiency floor (general mechanism) -cfg$gms$forcesuff21 <- "wood, woodfuel" # default (overridden for gF_freeze) +## common baseline: raw domestic feedstocks BRA should not import (model imports them +## even with no cap despite f21~1.0 -> artifacts). wood/woodfuel + cane/cassava/molasses. +cfg$gms$forcesuff21 <- "wood, woodfuel, sugr_cane, cassav_sp, molasses" # (overridden for gF_freeze) cfg$gms$policy_countries21 <- "BRA" cfg$gms$c32_aff_policy <- "npi"; cfg$gms$c35_ad_policy <- "npi"; cfg$gms$c35_aolc_policy <- "npi" cfg$gms$c_timesteps <- "5year2050" # <-- HORIZON knob: "coup2100" for 2100 cfg$output <- c("rds_report") cfg$results_folder <- "output/:title:" # undated folders -> stable names cfg$sequential <- FALSE -cfg$qos <- "standby" # many runs > priority MaxJobsPU cap CAPOFFSET <- 50 # nominal reported->cap offset reps_main <- c(-1000, -500, -250, -100, -50, 0, 50, 100, 250, 500) # C, A, F reps_B <- c(-1000, -500, -250, -100) # B trimmed (<= -63 floor) -# all BRA commodities with f21_self_suff > 1 (net exporters) + wood/woodfuel (gF_freeze) -FREEZE_LIST <- paste("wood, woodfuel, fibres, soybean, groundnut, sugar, oilcakes,", - "livst_pig, maiz, livst_chick, others, livst_rum, alcohol, oils,", - "rice_pro, livst_milk, cottn_pro, brans, cassav_sp, livst_egg") +# all BRA commodities with f21_self_suff >= 1 (net exporters + the balanced raw staples +# sugr_cane/molasses that the model otherwise imports) + wood/woodfuel (gF_freeze) +FREEZE_LIST <- paste("wood, woodfuel, sugr_cane, cassav_sp, molasses, fibres, soybean,", + "groundnut, sugar, oilcakes, livst_pig, maiz, livst_chick, others,", + "livst_rum, alcohol, oils, rice_pro, livst_milk, cottn_pro, brans, livst_egg") reptag <- function(r) if (r == 0) "rep000" else sprintf("rep%s%d", if (r < 0) "M" else "P", abs(r)) launch <- function(cfg, title) { cfg$title <- title; start_run(cfg, codeCheck = FALSE) } diff --git a/scripts/start/nzb_hpc_grid.R b/scripts/start/nzb_hpc_grid.R deleted file mode 100644 index d836a6f87d..0000000000 --- a/scripts/start/nzb_hpc_grid.R +++ /dev/null @@ -1,160 +0,0 @@ -## nzb_hpc_grid.R =============================================================== -## Comprehensive NZB test grid for the PIK HPC (SLURM). One start script; each -## start_run() -> one SLURM job. Launch on the LOGIN node with submit=direct. -## -## PREREQUISITE (run ONCE on login first, to warm the input cache and avoid the -## H12-fallback trap): Rscript scripts/start/download_data_BRA.R -## then verify core/sets.gms shows `Regionscode: 5638d5dc` + 13 regions (incl. BRA). -## -## Launch: Rscript start.R runscripts=nzb_hpc_grid submit=direct -## re-run a subset: NZB_FAMILIES=A Rscript start.R runscripts=nzb_hpc_grid submit=direct -## -## ---- TIER SWITCHES (edit these 2 lines to flip medium <-> light) ------------------- -## medium (~63 runs): STEP_AB=50 ; B_AR=c(TRUE,FALSE) -## light (~43 runs): STEP_AB=100; B_AR=c(TRUE) -STEP_AB <- 100 # cap-ladder step for families A & B (C is always 50) [LIGHT] -B_AR <- c(TRUE) # A/R on/off in family B [LIGHT] -## which families to run (env override for partial re-runs); default = all -FAMILIES <- strsplit(Sys.getenv("NZB_FAMILIES", "C,A,B,0"), ",")[[1]] -## ------------------------------------------------------------------------------------ -## -## DESIGN (indexed by ACHIEVED reported GWP100AR6|Land BRA AFOLU 2050; nocc; AR6 GWP -## baked into cap_apr26_reg/preloop.gms; wood self-sufficiency forced for BRA): -## Spine : parametric BRA cap, reported ladder {-200..+200} (cap target = reported+71; -## dashboard re-indexes on achieved). -## Fam C : conservation {WDPA, 30by30, HalfEarth} x cap ladder + ref. Cap ALONE -## (forced 1.5C MACC, no price). HalfEarth = current dashboard corner (redo). -## Fam A : "BRA does not act alone" - RoW pursues 2C (PkBudg1000 price + price-induced -## A/R + 2C 2nd-gen bioenergy demand); BRA capped, unpriced, and BRA's own -## bioenergy demand held at BASELINE (NPi2025; in NZB it comes from MACRO). -## RoW-only via policy_countries56 / scen_countries60 = BRA split. Cons=HalfEarth. -## 'context-off' == Family C HalfEarth (RoW at current policies), so not re-run. -## Fam B : cap PLUS a BRA 1.5C CO2 price (PkBudg650) driving price-induced A/R and -## price-driven MACC; A/R on/off. Cons=HalfEarth. Tests whether the price -## deepens CO2 below the cap alone (compare B vs C-HalfEarth). -## Anchor: NPI only, no MACC/restore/price/cap ("do nothing"). -## -## Cap families (C, A) force 1.5C MACC (BRA has no own price). Family B is price-driven. -## A/R (s56_c_price_induced_aff) only bites where a price applies: RoW in A, BRA in B. -## ============================================================================ -library(lucode2); library(gms); library(magpie4) -source("config/default.cfg"); source("scripts/start_functions.R") - -# ---- input + infra (BRA-H13 W3; on HPC download_distribute falls back to local mirrors) ---- -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) -cfg$force_download <- FALSE; cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE -cfg <- setScenario(cfg, "nocc") - -# ---- common GHG-policy / trade / horizon (all runs) -------------------------------- -cfg$gms$ghg_policy <- "cap_apr26_reg" # AR6 GWP baked in (preloop.gms:131-133) -cfg$gms$c56_cap_policy <- "all" # soil incl. (PR #904) -cfg$gms$s56_source_bounds_on <- 0 -cfg$gms$policy_countries56 <- "BRA" -cfg$gms$s21_force_selfsuff <- 1 # wood self-suff via the general floor (former s21_force_wood_selfsuff) -cfg$gms$forcesuff21 <- "wood, woodfuel" -cfg$gms$policy_countries21 <- "BRA" -cfg$gms$c32_aff_policy <- "npi"; cfg$gms$c35_ad_policy <- "npi"; cfg$gms$c35_aolc_policy <- "npi" -cfg$gms$c_timesteps <- "5year2050" # <-- HORIZON knob: "coup2100" for 2100 -cfg$output <- c("rds_report") -cfg$results_folder <- "output/:title:" # undated folders (drops :date:) -> stable names -cfg$sequential <- FALSE -cfg$qos <- "standby" # many runs > priority MaxJobsPU cap - -CAPOFFSET <- 71 # reported = cap - 71 (wood-SS on) -reps_main <- seq(-200, 200, by = 50) # family C ladder -reps_ab <- seq(-200, 200, by = STEP_AB) # families A & B ladder - -reptag <- function(r) if (r == 0) "rep000" else sprintf("rep%s%03d", if (r < 0) "M" else "P", abs(r)) -launch <- function(cfg, title) { cfg$title <- title; start_run(cfg, codeCheck = FALSE) } - -# ---- lever helpers ----------------------------------------------------------------- -macc_forced <- function(cfg) { # forced 1.5C MACC, faded 2025->2050 - for (s in c("n_soil","n_awms","ch4_rice","ch4_entferm","ch4_awms")) - cfg$gms[[paste0("s57_maxmac_", s)]] <- 106 - cfg$gms$s57_maxmac_fadein <- 1 - cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 - cfg -} -macc_pricedriven <- function(cfg) { # abatement follows the CO2 price - for (s in c("n_soil","n_awms","ch4_rice","ch4_entferm","ch4_awms")) - cfg$gms[[paste0("s57_maxmac_", s)]] <- -1 - cfg$gms$s57_maxmac_fadein <- 0 - cfg -} -conservation <- function(cfg, scen) { # "none"(=WDPA base) / "30by30" / "PBL_HalfEarth" - cfg$gms$c22_protect_scenario <- scen - cfg$gms$c22_protect_scenario_noselect <- "none" - cfg$gms$s22_restore_land <- if (scen == "none") 0 else 1 - cfg$gms$policy_countries22 <- "BRA" - cfg -} -set_cap <- function(cfg, reported) { - cfg$gms$s56_emis_cap_parametric <- 1 - cfg$gms$s56_emis_cap_start_year <- 2035 - cfg$gms$s56_emis_cap_start_value <- 600 - cfg$gms$s56_emis_cap_target_year <- 2050 - cfg$gms$s56_emis_cap_target <- reported + CAPOFFSET - cfg -} -set_nocap <- function(cfg) { - cfg$gms$s56_emis_cap_parametric <- 0; cfg$gms$c56_emis_cap_scenario <- "none"; cfg -} -ladder <- function(base, fam, reps) { # ref (no-cap) + cap ladder - launch(set_nocap(base), sprintf("nzb_%s_ref", fam)) - for (r in reps) launch(set_cap(base, r), sprintf("nzb_%s_%s", fam, reptag(r))) -} - -# ============================ Family C: conservation (cap alone) ==================== -if ("C" %in% FAMILIES) for (cons in list(list(tag="wdpa", scen="none"), - list(tag="30by30", scen="30by30"), - list(tag="half", scen="PBL_HalfEarth"))) { - base <- conservation(macc_forced(cfg), cons$scen) - base$gms$c56_pollutant_prices <- "none" - base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" - base$gms$s56_c_price_induced_aff <- 0 - ladder(base, sprintf("gC_%s", cons$tag), reps_main) -} - -# ===================== Family A: RoW pursues 2C, BRA capped (BRA bioen baseline) ===== -if ("A" %in% FAMILIES) { - base <- conservation(macc_forced(cfg), "PBL_HalfEarth") - base$gms$c56_pollutant_prices <- "none" # BRA capped, not priced - base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C price - base$gms$s56_c_price_induced_aff <- 1 # price-induced A/R (RoW) - base$gms$scen_countries60 <- "BRA" # split BRA vs RoW bioenergy - base$gms$c60_2ndgen_biodem <- "R34M410-SSP2-NPi2025" # BRA baseline (MACRO in NZB) - base$gms$c60_2ndgen_biodem_noselect <- "R34M410-SSP2-PkBudg1000" # RoW 2C bioenergy demand - ladder(base, "gA_RoW2C", reps_ab) -} - -# ===================== Family B: cap + BRA 1.5C price (drives A/R + MACC) ============ -if ("B" %in% FAMILIES) for (ar in B_AR) { - base <- conservation(macc_pricedriven(cfg), "PBL_HalfEarth") - base$gms$c56_pollutant_prices <- "R34M410-SSP2-PkBudg650" # BRA priced 1.5C - base$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" # RoW current policies - base$gms$s56_c_price_induced_aff <- if (ar) 1 else 0 - ladder(base, sprintf("gB_ar%s", if (ar) "ON" else "OFF"), reps_ab) -} - -# ===================== Anchor: NPI only (no MACC / restore / price / cap) ============ -if ("0" %in% FAMILIES) { - anchor <- set_nocap(conservation(macc_pricedriven(cfg), "none")) - anchor$gms$c56_pollutant_prices <- "none" - anchor$gms$c56_pollutant_prices_noselect <- "R34M410-SSP2-NPi2025" - anchor$gms$s56_c_price_induced_aff <- 0 - launch(anchor, "nzb_g0_npi") -} - -nC <- if ("C" %in% FAMILIES) 3 * (length(reps_main) + 1) else 0 -nA <- if ("A" %in% FAMILIES) 1 * (length(reps_ab) + 1) else 0 -nB <- if ("B" %in% FAMILIES) length(B_AR) * (length(reps_ab) + 1) else 0 -n0 <- if ("0" %in% FAMILIES) 1 else 0 -cat(sprintf("== nzb_hpc_grid launched [%s]: C(%d)+A(%d)+B(%d)+anchor(%d) = %d jobs ==\n", - paste(FAMILIES, collapse=","), nC, nA, nB, n0, nC + nA + nB + n0)) diff --git a/scripts/start/nzb_nocap_corners.R b/scripts/start/nzb_nocap_corners.R deleted file mode 100644 index 76f63f01d6..0000000000 --- a/scripts/start/nzb_nocap_corners.R +++ /dev/null @@ -1,63 +0,0 @@ -## nzb_nocap_corners.R --------------------------------------------------------- -## The 3 MISSING no-cap (R0) references, one per lever corner that lacks one. -## {MACC on, restore on} already exists (nzb_R0_ref). This adds: -## nzb_R0_mON_rOFF (MACC on, restore off) -## nzb_R0_mOFF_rON (MACC off, restore on) -## nzb_R0_mOFF_rOFF (MACC off, restore off) -## Each = non-binding cap (c56_emis_cap_scenario "none" -> p56_emis_cap 1e6), so -## the dashboard's "no cap" reference matches the toggled corner exactly instead -## of falling back to the {on,on} R0. Same input/calibration as the library. -## All 3 fit one wave (<=6 on 24 GB). Output: rds_report. -## --------------------------------------------------------------------------- -library(lucode2); library(gms); library(magpie4) -source("config/default.cfg"); source("scripts/start_functions.R") - -cfg$input <- c(regional = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_magpie.tgz", - cellular = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_d8411e75_cellularmagpie_c200_MRI-ESM2-0-ssp245_lpjml-8e6c5eb1_clusterweight-d0236589.tgz", - validation = "rev4.131.9001BRA_H13_C200_W3_MapbiomasIBGE_5638d5dc_92e02314_validation.tgz", - additional = "additional_data_rev4.65.tgz", - calibration = "calibration_BRA_H13_C200_W3_MapbiomasIBGE_18Jun26.tgz") -cfg$repositories <- append(list("https://rse.pik-potsdam.de/data/magpie/public" = NULL), - getOption("magpie_repos")) -cfg$force_download <- FALSE; cfg$force_replace <- TRUE -cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE -cfg <- setScenario(cfg, "nocc") - -# ---- common config (== library, but NON-BINDING cap) ----------------------- -cfg$gms$ghg_policy <- "cap_apr26_reg" -cfg$gms$c56_cap_policy <- "all" -cfg$gms$c56_emis_cap_scenario <- "none" # p56_emis_cap = 1e6 -> never binds -cfg$gms$s56_emis_cap_parametric <- 0 # force OFF (input.gms has drift from prior runs) -cfg$gms$s56_source_bounds_on <- 0 -cfg$gms$c56_pollutant_prices <- "none" -cfg$gms$s56_c_price_induced_aff <- 0 -cfg$gms$c_timesteps <- "5year2050" -cfg$output <- c("rds_report") -cfg$sequential <- FALSE - -apply_macc <- function(cfg, on){ - v <- if(on) 106 else -1 - cfg$gms$s57_maxmac_n_soil <- v; cfg$gms$s57_maxmac_n_awms <- v - cfg$gms$s57_maxmac_ch4_rice <- v; cfg$gms$s57_maxmac_ch4_entferm <- v - cfg$gms$s57_maxmac_ch4_awms <- v - cfg$gms$s57_maxmac_fadein <- if(on) 1 else 0 - cfg$gms$s57_maxmac_fadein_start <- 2025; cfg$gms$s57_maxmac_fadein_end <- 2050 - cfg -} -apply_rest <- function(cfg, on){ - if(on){ cfg$gms$c22_protect_scenario <- "PBL_HalfEarth"; cfg$gms$s22_restore_land <- 1 } - else { cfg$gms$c22_protect_scenario <- "none"; cfg$gms$s22_restore_land <- 0 } - cfg$gms$c22_protect_scenario_noselect <- "none" - cfg$gms$policy_countries22 <- "BRA" - cfg -} -launch <- function(cfg, macc, rest){ - cfg <- apply_macc(cfg, macc); cfg <- apply_rest(cfg, rest) - cfg$title <- sprintf("nzb_R0_m%s_r%s", if(macc)"ON" else"OFF", if(rest)"ON" else"OFF") - start_run(cfg, codeCheck = FALSE) - cfg$title -} - -corners <- list(c(TRUE, FALSE), c(FALSE, TRUE), c(FALSE, FALSE)) # the 3 missing -titles <- sapply(corners, function(cc) launch(cfg, cc[1], cc[2])) -cat("== launched 3 no-cap corner runs ==\n"); print(unname(titles))