Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions config/scenario_config_nzb.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
f;nzb_base;gC_wdpa;gC_30by30;gC_half;gA_RoW2C;gB_price;gF_freeze;g0_npi
gms$ghg_policy;cap_apr26_reg;;;;;;;
gms$c56_cap_policy;all;;;;;;;
gms$s56_source_bounds_on;0;;;;;;;
gms$policy_countries56;BRA;;;;;;;
gms$s21_force_selfsuff;1;;;;;;;
gms$forcesuff21;wood, woodfuel, sugr_cane, cassav_sp, molasses;;;;;;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;
gms$policy_countries21;BRA;;;;;;;
gms$c32_aff_policy;npi;;;;;;;
gms$c35_ad_policy;npi;;;;;;;
gms$c35_aolc_policy;npi;;;;;;;
gms$c_timesteps;5year2050;;;;;;;
gms$c22_protect_scenario_noselect;none;;;;;;;
gms$policy_countries22;BRA;;;;;;;
gms$s57_maxmac_n_soil;;106;106;106;106;-1;106;-1
gms$s57_maxmac_n_awms;;106;106;106;106;-1;106;-1
gms$s57_maxmac_ch4_rice;;106;106;106;106;-1;106;-1
gms$s57_maxmac_ch4_entferm;;106;106;106;106;-1;106;-1
gms$s57_maxmac_ch4_awms;;106;106;106;106;-1;106;-1
gms$s57_maxmac_fadein;;1;1;1;1;0;1;0
gms$s57_maxmac_fadein_start;;2025;2025;2025;2025;;2025;
gms$s57_maxmac_fadein_end;;2050;2050;2050;2050;;2050;
gms$c22_protect_scenario;;none;30by30;PBL_HalfEarth;none;none;none;none
gms$s22_restore_land;;0;1;1;0;0;0;0
gms$c56_pollutant_prices;;none;none;none;none;R34M410-SSP2-PkBudg650;none;none
gms$c56_pollutant_prices_noselect;;R34M410-SSP2-NPi2025;R34M410-SSP2-NPi2025;R34M410-SSP2-NPi2025;R34M410-SSP2-PkBudg1000;R34M410-SSP2-NPi2025;R34M410-SSP2-NPi2025;R34M410-SSP2-NPi2025
gms$s56_c_price_induced_aff;;0;0;0;1;1;0;0
gms$scen_countries60;;;;;BRA;;;
gms$c60_2ndgen_biodem;;;;;R34M410-SSP2-NPi2025;;;
gms$c60_2ndgen_biodem_noselect;;;;;R34M410-SSP2-PkBudg1000;;;
136 changes: 136 additions & 0 deletions scripts/start/nzb_launch.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
## nzb_launch.R ================================================================
## Launch ONE Net-Zero-Brazil scenario, defined as a column in
## config/scenario_config_nzb.csv (FSEC-style base+delta), with the cap supplied
## at launch. Companion to the batch grid scripts/start/nzb_export_grid.R -- same
## families, but one run per call and driven by the CSV instead of R branching.
##
## INPUTS (env vars, or key=value CLI args):
## scenario (NZB_SCENARIO) required. A column of scenario_config_nzb.csv:
## gC_wdpa | gC_30by30 | gC_half | gA_RoW2C | gB_price | gF_freeze | g0_npi
## target (NZB_TARGET) optional. Desired REPORTED AFOLU 2050 (GWP100AR6|Land, Mt CO2eq).
## The script sets the emissions cap to cap = target + OFFSET_MT (see OFFSET
## below) and enables the parametric ramp 2035->2050. This is the platform knob.
## cap (NZB_CAP) optional. RAW emissions cap value (s56_emis_cap_target, Mt CO2eq),
## set verbatim -- bypasses the offset. Reported AFOLU then comes out ~ cap - OFFSET_MT.
## -> Give EITHER target OR cap (not both). Omit both -> the scenario's no-cap reference run.
##
## OFFSET (reported <-> cap). The cap bounds vm_emissions_reg, a SUPERSET of the reported
## GWP100AR6|Land AFOLU, so reported ~ cap - OFFSET_MT with OFFSET_MT = 63 Mt (median across
## families; ~+50 of it is the intact-peatland CH4+DOC slice the cap includes but the report
## excludes). Hence cap = target + 63. The per-family spread is ~57-71 and the reachable-target
## range is per family -- see NZB_scenario_config_approach.md. Retune via OFFSET_MT below.
##
## LAUNCH (recommended) -- run the script DIRECTLY, bypassing start.R. This avoids
## start.R's interactive "Update now? (Y/n)" renv prompt entirely (that check lives only
## in start.R, not .Rprofile); renv still activates via .Rprofile and start_run() submits
## the model. No submit= needed.
## NZB_SCENARIO=gF_freeze NZB_TARGET=-100 Rscript scripts/start/nzb_launch.R # target reported AFOLU
## NZB_SCENARIO=gF_freeze NZB_CAP=-37 Rscript scripts/start/nzb_launch.R # raw cap (= -100 + 63)
## NZB_SCENARIO=g0_npi Rscript scripts/start/nzb_launch.R # no cap -> ref run
## (CLI args also work here: Rscript scripts/start/nzb_launch.R scenario=gF_freeze target=-100)
##
## ALTERNATIVE via start.R -- pass submit=direct (else start.R prompts for a submission
## type) and it will run the "Update now?" check first:
## NZB_SCENARIO=gF_freeze NZB_CAP=-37 Rscript start.R runscripts=nzb_launch submit=direct
## CLI scenario=/cap= reach the script only with submit=direct (in-process source);
## background/SLURM submit modes spawn a fresh Rscript that drops CLI args -- env vars
## are inherited and always work.
##
## The CSV is the scenario registry; a platform edits/adds columns or just picks a
## column + cap. No config text is generated as code -> nothing to mis-template.
## ============================================================================
library(lucode2); library(gms); library(magpie4)
source("config/default.cfg"); source("scripts/start_functions.R")

SCEN_CSV <- "config/scenario_config_nzb.csv"

# ---- read launch args (CLI key=value first, else NZB_* env) -------------------------
.args <- commandArgs(trailingOnly = TRUE)
getarg <- function(key) {
hit <- grep(paste0("^", key, "="), .args, value = TRUE)
if (length(hit)) return(sub(paste0("^", key, "="), "", hit[1]))
e <- Sys.getenv(paste0("NZB_", toupper(key)), ""); if (nzchar(e)) e else NA_character_
}
scenario <- getarg("scenario")
target_raw <- getarg("target")
cap_raw <- getarg("cap")
have <- function(x) !is.na(x) && nzchar(x)

valid <- setdiff(colnames(read.csv2(SCEN_CSV, check.names = FALSE, nrows = 1))[-1], c("", "nzb_base"))
if (is.na(scenario))
stop("nzb_launch: no scenario given. Set NZB_SCENARIO=<col> (or scenario=<col>).\n",
" columns: ", paste(valid, collapse = ", "))
if (!scenario %in% valid)
stop("nzb_launch: scenario '", scenario, "' is not a column of ", SCEN_CSV, ".\n",
" columns: ", paste(valid, collapse = ", "))

# ---- resolve the scenario: nocc (native) + nzb_base + the chosen family -------------
# setScenario is MAgPIE's central scenario mechanism (base+delta overlay, as in FSEC),
# so the whole NZB registry rides it. One wrinkle: setScenario splits any comma-bearing
# cell into a character VECTOR -- here the list-valued GAMS *set* switch forcesuff21 (a
# subset of k_trade). A vector serialises to a valid GAMS set list via manipulateConfig
# (exactly like the ~249-element policy_countries* sets), so the MODEL is fine either
# way. But setScenario's own scalar re-comparison `if (from != to & to != "")` of an
# already-vectorised value on a SECOND overlaid column errors ("the condition has length
# > 1"). So we overlay the columns ONE AT A TIME and collapse forcesuff21 back to the
# single comma-string that default.cfg / nzb_export_grid.R use, after each call. The
# collapse round-trips the cell verbatim ('a, b' -> c('a',' b') -> 'a, b') and is a
# no-op when the family cell is empty (forcesuff21 already a length-1 string from base).
cfg <- setScenario(cfg, "nocc") # native climate-off scenario
for (col in c("nzb_base", scenario)) {
cfg <- setScenario(cfg, col, scenario_config = SCEN_CSV) # scalar deltas overlaid natively
cfg$gms$forcesuff21 <- paste(cfg$gms$forcesuff21, collapse = ",") # comma-list switch: vector -> single string
}

# ---- common run settings (not policy levers; same for every NZB run) ----------------
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$force_download <- FALSE; cfg$force_replace <- TRUE
cfg$recalibrate <- FALSE; cfg$recalibrate_landconversion_cost <- FALSE
cfg$output <- c("rds_report"); cfg$results_folder <- "output/:title:"; cfg$sequential <- FALSE

# ---- cap: from a reported-AFOLU target (cap = target + OFFSET_MT) or a raw cap value ------
# OFFSET_MT is the reported<->cap offset (see header): reported GWP100AR6|Land AFOLU ~ cap -
# OFFSET_MT, so cap = target_reported + OFFSET_MT. +63 Mt = median across families (~+50 is the
# intact-peatland CH4+DOC slice the cap includes but the report excludes). Retune here if needed.
OFFSET_MT <- 63

if (have(target_raw) && have(cap_raw))
stop("nzb_launch: give EITHER target= (reported AFOLU) OR cap= (raw s56_emis_cap_target), not both.")

cap <- NA_real_; from_target <- FALSE
if (have(target_raw)) {
target <- suppressWarnings(as.numeric(target_raw))
if (!is.finite(target)) stop("nzb_launch: target='", target_raw, "' is not a number.")
cap <- target + OFFSET_MT; from_target <- TRUE
message(sprintf("nzb_launch: reported-AFOLU target %+g Mt -> cap %+g Mt (offset +%g)",
target, cap, OFFSET_MT))
} else if (have(cap_raw)) {
cap <- suppressWarnings(as.numeric(cap_raw))
if (!is.finite(cap)) stop("nzb_launch: cap='", cap_raw, "' is not a number.")
}

if (is.finite(cap)) {
if (cap < -300 || cap > 600)
warning("nzb_launch: cap ", cap, " Mt is outside the tested band [-300, 600]; ",
"may be infeasible (on-slack) or non-binding. See the per-family reach table.")
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 <- cap
cfg$title <- sprintf("nzb_%s_%s", scenario,
if (from_target) sprintf("tgt%s%d", if (target < 0) "M" else "P", abs(round(target)))
else sprintf("cap%s%d", if (cap < 0) "M" else "P", abs(round(cap))))
} else {
# neither target nor cap: honour whatever the CSV/default set (parametric off = ref run)
cfg$title <- if (isTRUE(cfg$gms$s56_emis_cap_parametric == 1))
sprintf("nzb_%s_capCSV", scenario) else sprintf("nzb_%s_ref", scenario)
}

message("nzb_launch: scenario=", scenario, " title=", cfg$title,
" cap=", if (is.finite(cap)) cap else "(none/ref)")
start_run(cfg, codeCheck = FALSE)