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
2 changes: 1 addition & 1 deletion .buildlibrary
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ValidationKey: '55497344'
ValidationKey: '55784700'
AutocreateReadme: yes
AcceptedWarnings:
- 'Warning: package .* was built under R version'
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ jobs:
container:
image: ghcr.io/pik-piam/ci-image:latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Install
shell: Rscript {0}
run: |
options(repos = c(pikpiam = 'https://pik-piam.r-universe.dev',
CRAN = Sys.getenv('RSPM')))
pak::pak(".")
pak::pak(".", dependencies = 'all')
pak::pkg_install("tidyverse/tidytemplate")

- name: Build site
Expand All @@ -37,7 +37,7 @@ jobs:

- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4.5.0
uses: JamesIves/github-pages-deploy-action@v4.8.0
with:
clean: false
branch: gh-pages
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ cff-version: 1.2.0
message: If you use this software, please cite it using the metadata from this file.
type: software
title: 'mrvalidation: madrat data preparation for validation purposes'
version: 2.69.3
date-released: '2026-06-04'
version: 2.70.0
date-released: '2026-07-27'
abstract: Package contains routines to prepare data for validation exercises.
authors:
- family-names: Bodirsky
Expand Down
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Type: Package
Package: mrvalidation
Title: madrat data preparation for validation purposes
Version: 2.69.3
Date: 2026-06-04
Version: 2.70.0
Date: 2026-07-27
Authors@R: c(
person("Benjamin Leon", "Bodirsky", , "bodirsky@pik-potsdam.de", role = c("aut", "cre")),
person("Stephen", "Wirth", role = "aut"),
Expand Down
15 changes: 0 additions & 15 deletions R/calcValidAnnualCarbonLTS.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ calcValidAnnualCarbonLTS <- function(datasource = "Lauk_et_al") {
out <- emis
getNames(out) <- paste0(indicatorname, " (", unit, ")")

indicatornameRaw <- "Emissions|CO2|Land RAW|Land-use Change|Wood products|+|Storage"
raw <- emis
getNames(raw) <- paste0(indicatornameRaw, " (", unit, ")")
out <- mbind(out, raw)

out <- add_dimension(out, dim = 3.1, add = "scenario", nm = "historical")
out <- add_dimension(out, dim = 3.2, add = "model", nm = datasource)

Expand All @@ -41,11 +36,6 @@ calcValidAnnualCarbonLTS <- function(datasource = "Lauk_et_al") {

outHistorical <- annual[, future, , invert = TRUE]

indicatornameRaw <- "Emissions|CO2|Land RAW|Land-use Change|Wood products|+|Storage"
raw <- outHistorical
getNames(raw) <- paste0(indicatornameRaw, " (", unit, ")")
outHistorical <- mbind(outHistorical, raw)

outHistorical <- add_dimension(outHistorical, dim = 3.1, add = "scenario", nm = "historical")
outHistorical <- add_dimension(outHistorical, dim = 3.2, add = "model", nm = datasource)

Expand All @@ -66,11 +56,6 @@ calcValidAnnualCarbonLTS <- function(datasource = "Lauk_et_al") {

outProjection <- annual[, future, ]

indicatornameRaw <- "Emissions|CO2|Land RAW|Land-use Change|Wood products|+|Storage"
raw <- outProjection
getNames(raw) <- paste0(indicatornameRaw, " (", unit, ")")
outProjection <- mbind(outProjection, raw)

outProjection <- add_dimension(outProjection, dim = 3.1, add = "scenario", nm = "projection")
outProjection <- add_dimension(outProjection, dim = 3.2, add = "model", nm = datasource)

Expand Down
19 changes: 10 additions & 9 deletions R/calcValidEmisLucGasser.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,34 @@ calcValidEmisLucGasser <- function(subtype = "bookkeeping") {
extrapolation_type = "constant", integrate_interpolated_years = TRUE)
names(dimnames(out))[3] <- "scenario.model.variable"
} else if (subtype %in% "bookkeeping") {
# "Gasser et al 2020" = OSCAR bookkeeping ELUC: ex-peat and direct (no indirect/Grassi term); it is
# essentially the same model as the GCB "OSCAR" column. For the full peat/indirect scope of the
# LUC-CO2 validation cloud see calcValidGlobalCarbonBudget (@details).
model <- "Gasser et al 2020"
## Conversion from Pg to Mt and C to CO2
out <- readSource("Gasser", subtype = subtype, convert = TRUE) * 1000 * 44 / 12
out1 <- out[, , c("gross_luc_emis", "regrowth_luc_emis")]
getNames(out1) <- c("Gross LUC", "Regrowth")
getNames(out1) <- paste0("Emissions|CO2|Land|Land-use Change|+|", getNames(out1), " (Mt CO2/yr)")
raw1 <- out[, , c("gross_luc_emis", "regrowth_luc_emis")]
getNames(raw1) <- c("Gross LUC", "Regrowth")
getNames(raw1) <- paste0("Emissions|CO2|Land RAW|Land-use Change|+|", getNames(raw1), " (Mt CO2/yr)")
out1 <- mbind(out1, raw1)
out1 <- add_dimension(out1, dim = 3.1, add = "scenario", nm = "historical")
out1 <- add_dimension(out1, dim = 3.2, add = "model", nm = model)
names(dimnames(out1))[3] <- "scenario.model.variable"

out2 <- out[, , "overall"]
getNames(out2) <- c("Emissions|CO2|Land|+|Land-use Change")
getNames(out2) <- paste0(getNames(out2), " (Mt CO2/yr)")
raw2 <- out[, , "overall"]
getNames(raw2) <- c("Emissions|CO2|Land RAW|+|Land-use Change")
getNames(raw2) <- paste0(getNames(raw2), " (Mt CO2/yr)")
out2 <- mbind(out2, raw2)

out2 <- add_dimension(out2, dim = 3.1, add = "scenario", nm = "historical")
out2 <- add_dimension(out2, dim = 3.2, add = "model", nm = model)
names(dimnames(out2))[3] <- "scenario.model.variable"

out <- mbind(out1, out2)

# ex-peatland alias: Gasser (= OSCAR bookkeeping) is ex-peat, so also expose Land-use Change under the
# peat-excluded name to line up with MAgPIE's Emissions|CO2|Land|Land-use Change|Excl Peatland memo
# (like-for-like bookkeeping comparison; see calcValidGlobalCarbonBudget @details).
exclPeat <- out[, , "Emissions|CO2|Land|+|Land-use Change (Mt CO2/yr)"]
getNames(exclPeat, dim = "variable") <- "Emissions|CO2|Land|Land-use Change|Excl Peatland (Mt CO2/yr)"
out <- mbind(out, exclPeat)
} else {
stop("Invalid subtype. See function description for valid subtypes.")
}
Expand Down
5 changes: 0 additions & 5 deletions R/calcValidEmissions.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@
calcValidEmissions <- function(datasource = "CEDS") {

out <- calcOutput("LandEmissions", aggregate = FALSE, datasource = datasource, warnNA = FALSE)
if ("Emissions|CO2|Land|+|Land-use Change (Mt CO2/yr)" %in% getNames(out, dim = 3)) {
emisCO2 <- out[, , "Emissions|CO2|Land|+|Land-use Change (Mt CO2/yr)"]
getNames(emisCO2, dim = 3) <- "Emissions|CO2|Land RAW|+|Land-use Change (Mt CO2/yr)"
out <- mbind(out, emisCO2)
}

return(list(x = out,
weight = NULL,
Expand Down
7 changes: 7 additions & 0 deletions R/calcValidEmissionsAFOLU.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ calcValidEmissionsAFOLU <- function(datasource = "FAO", cumulative = FALSE) {
return(x)
}

# NB on the CO2 land-use-change component below: FAO_EmisLUC and EDGAR_LU are national-statistics /
# inventory LULUCF series. As ingested they are positive LUC-scale SOURCES (~2800-5400 Mt CO2/yr): FAO is
# FAOSTAT's net "Land Use total" (forest sink included but modest, still a source), EDGAR is LULUCF CO2 -
# neither carries a net-flux or Indirect sink series. They therefore sit in the same LUC-source cloud as
# the bookkeeping ELUC estimates and compare to MAgPIE's Emissions|CO2|Land|+|Land-use Change, NOT to net
# Emissions|CO2|Land. (They are incl-peat - drained organic soils - but that term is small relative to the
# source.) See calcValidGlobalCarbonBudget (@details) for the full peat/indirect scope of the LUC-CO2 cloud.
if (datasource == "FAO") {
# FAO agricultural emissions (inclusive of the burning of crop residues)
faoAg <- calcOutput("ValidEmissions", datasource = "FAO_EmisAg", aggregate = FALSE, warnNA = FALSE)
Expand Down
14 changes: 12 additions & 2 deletions R/calcValidGS.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,28 @@ calcValidGS <- function(datasource = "FRA2025", indicator = "relative") {

if (datasource == "FRA2025") {
a <- collapseNames(readSource("FRA2025", subtype = "growing_stock", convert = TRUE))
# The FRA2025 source labels the primary/introduced growing-stock totals with an inconsistent
# "gs_total_" prefix (all other categories use "gs_tot_"); normalise it so the category drops
# and the "gs_tot_" name cleanup below match for every category (otherwise the absolute branch
# leaks "introduced" and renders garbled names like "GS Total Primary Forest").
getNames(a) <- gsub("gs_total_", "gs_tot_", getNames(a))
indicatorname <- "Resources|Growing Stock|"

if (indicator == "absolute") {
absolute <- a[, , grep(pattern = "gs_tot", x = getNames(a), value = TRUE)][, , "gs_tot_introduced", invert = TRUE]
# drop the "introduced" plantation series and the broken FRA primary-forest series
# (primary GS ~18 m3/ha area-weighted -> implausible; FRA reports it too sparsely to use)
absolute <- a[, , grep(pattern = "gs_tot", x = getNames(a), value = TRUE)]
absolute <- absolute[, , c("gs_tot_introduced", "gs_tot_primary"), invert = TRUE]
indicatorname <- paste0(indicatorname, indicator, "|+|")
out <- absolute
getNames(out) <- gsub(pattern = "gs_tot_", replacement = "", x = getNames(out))
getNames(out) <- FRAnames(getNames(out))
unit <- "Mm3"
weight <- NULL
} else if (indicator == "relative") {
relative <- a[, , grep(pattern = "gs_ha", x = getNames(a), value = TRUE)][, , "gs_ha_introduced", invert = TRUE]
# drop the "introduced" plantation series and the broken FRA primary-forest series (see above)
relative <- a[, , grep(pattern = "gs_ha", x = getNames(a), value = TRUE)]
relative <- relative[, , c("gs_ha_introduced", "gs_ha_primary"), invert = TRUE]
indicatorname <- paste0(indicatorname, indicator, "|+|")
out <- relative
getNames(out) <- gsub(pattern = "gs_ha_", replacement = "", x = getNames(out))
Expand Down
64 changes: 61 additions & 3 deletions R/calcValidGlobalCarbonBudget.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
#' @title ValidGlobalCarbonBudget
#' @description validation for total and cumulative land emissions from the Global Carbon Budget, including
#' all bookkeeping models
#'
#' @details
#' The historical series pooled under \code{Emissions|CO2|Land|+|Land-use Change} are all LUC-scale CO2
#' SOURCES and are broadly comparable to MAgPIE's \code{+|Land-use Change}. Verified against the ingested
#' validation data (not the parent publications), they form a single positive cloud (Mt CO2/yr, World,
#' 2000-2010): bookkeeping BLUE/OSCAR/GCB/H&C ~2600-6600 and the national-statistics series
#' FAO_EmisLUC/EDGAR_LU/PRIMAPhist ~2800-5400 - the latter numerically indistinguishable from the
#' bookkeeping cloud. They differ mainly on PEAT; a second, conceptual axis (INDIRECT/Grassi) matters in
#' principle but is NOT represented in the ingested data (see Axis 2):
#' \tabular{lll}{
#' \strong{source} \tab \strong{peat} \tab \strong{nature (as ingested)} \cr
#' BLUE, OSCAR, H&C2023 \tab excl \tab bookkeeping ELUC (direct, ex-peat) \cr
#' GCB (this fn) \tab excl \tab = mean(BLUE, OSCAR, H&C2023) \cr
#' Gasser et al 2020 \tab excl \tab OSCAR bookkeeping \cr
#' FAO_EmisLUC \tab incl \tab FAOSTAT net LULUCF ("Land Use total"), a source \cr
#' EDGAR_LU \tab incl \tab EDGAR LULUCF CO2, a source \cr
#' PRIMAPhist \tab incl \tab PRIMAP-hist CAT5 (LUCF) CO2, a source \cr
#' }
#'
#' Axis 1 - PEAT. Bookkeeping estimates exclude peat drainage/fire; the national-statistics series include
#' it (drained organic soils). MAgPIE's Land-use Change INCLUDES peat (separable via its \code{+|Peatland}
#' child), so the peat-clean bookkeeping comparison uses Land-use Change net of that peat child (magpie4's
#' \code{...|Land-use Change|Excl Peatland} line, where present, provides this directly). The peat term
#' (~1-1.5 Gt CO2/yr) is small relative to the source magnitude and does not move the inventories out of
#' the LUC cloud.
#'
#' Axis 2 - INDIRECT (Grassi) - NOT represented in the ingested data. In principle the bookkeeping-vs-NGHGI
#' gap (~5 Gt CO2/yr; Grassi et al. 2021, doi:10.1038/s41558-021-01033-6) arises because country inventories,
#' reporting the sink-inclusive NET LULUCF over a large managed-land area, embed the environmental sink and
#' sit far BELOW bookkeeping ELUC - which would make net \code{Emissions|CO2|Land} the matching counterpart.
#' BUT none of the FAO_EmisLUC/EDGAR_LU/PRIMAPhist series ingested here is that Grassi-adjusted NGHGI net:
#' FAO is FAOSTAT's net "Land Use total" (its forest sink included but modest, so still a ~4 Gt SOURCE),
#' EDGAR/PRIMAP are LULUCF CO2 series - all positive, LUC-scale, none carrying a net-flux or Indirect sink
#' series. They must therefore be compared to MAgPIE's \code{+|Land-use Change} like the bookkeeping sources,
#' NOT to net Land. The sink-inclusive NGHGI-net quantity Grassi contrasts with bookkeeping is absent from
#' this validation cloud, so MAgPIE's own \code{+|Indirect} (its Grassi managed-land sink ~-5.6 Gt CO2/yr,
#' \code{i52_land_carbon_sink}) has no inventory counterpart here to validate against.
#'
#' GCB note - the GCB column ingested here is the bookkeeping-model MEAN and is EX-peat: GCB ==
#' mean(BLUE, OSCAR, H&C2023) exactly (World 2020: 4298 == mean(5607, 4724, 2564)). The published GCB
#' ELUC additionally adds peat drainage/fire (a separate GCB.xlsx column) not folded into the ingested
#' net. GCB's peat column exists in the workbook but is intentionally not ingested (it could not be an
#' additive child of Land-use Change, since GCB's net excludes it).
#'
#' Do NOT benchmark net Land against GCB: the only Indirect / net \code{Emissions|CO2|Land} series here is
#' GCB's, where Indirect = the GCB terrestrial sink S_LAND over ALL land (World 2020: -11403 Mt CO2/yr,
#' ~the whole-biosphere sink), NOT the managed-land Grassi quantity MAgPIE reports.
#'
#' @author Michael Crawford
#'
#' @param cumulative cumulative from y2000
Expand Down Expand Up @@ -42,9 +90,19 @@ calcValidGlobalCarbonBudget <- function(cumulative = FALSE) {
}
magclass::getNames(allOut, dim = 3) <- reportingNames

allOut2 <- allOut
magclass::getNames(allOut2, dim = 3) <- sub("\\|Land", "\\|Land RAW", reportingNames)
allOut <- mbind(allOut, allOut2)
# Ex-peatland alias: these bookkeeping sources are already ex-peat, so also expose their Land-use
# Change under MAgPIE's peat-excluded memo name (Emissions|CO2|Land|Land-use Change|Excl Peatland)
# for a like-for-like comparison. See @details.
if (cumulative) {
lucVar <- "Emissions|CO2|Land|Cumulative|+|Land-use Change (Gt CO2)"
exclVar <- "Emissions|CO2|Land|Cumulative|Land-use Change|Excl Peatland (Gt CO2)"
} else {
lucVar <- "Emissions|CO2|Land|+|Land-use Change (Mt CO2/yr)"
exclVar <- "Emissions|CO2|Land|Land-use Change|Excl Peatland (Mt CO2/yr)"
}
elucExclPeat <- allOut[, , lucVar]
magclass::getNames(elucExclPeat, dim = 3) <- exclVar
allOut <- mbind(allOut, elucExclPeat)

return(list(
x = allOut,
Expand Down
6 changes: 4 additions & 2 deletions R/calcValidLand.R
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,16 @@ calcValidLand <- function(datasource = "MAgPIEown") {
"plantationForest",
"otherPlantedForest")]

# Planted forest keeps FRA's split into timber plantations and other planted forest, matching the
# model forestry pools.
getNames(fraForest2025, dim = 1) <- c("Resources|Land Cover|+|Forest",
"Resources|Land Cover|Forest|+|Natural Forest",
"Resources|Land Cover|Forest|Natural Forest|+|Primary Forest",
"Resources|Land Cover|Forest|Natural Forest|+|Secondary Forest",
"Resources|Land Cover|Cropland|+|Tree Cover",
"Resources|Land Cover|Forest|+|Planted Forest",
"Resources|Land Cover|Forest|Planted Forest|Plantations|+|Timber",
"Resources|Land Cover|Forest|Planted Forest|Natural|+|NPI_NDC AR")
"Resources|Land Cover|Forest|Planted Forest|+|Timber",
"Resources|Land Cover|Forest|Planted Forest|+|Other Planted")
yPast <- magpiesets::findset("past", noset = "original")
yPast <- as.integer(substring(yPast, 2, 5))
yData <- getYears(fraForest2025, as.integer = TRUE)
Expand Down
Loading
Loading