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
6 changes: 4 additions & 2 deletions .buildlibrary
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
ValidationKey: '22955016'
ValidationKey: '23132480'
AutocreateReadme: yes
AutocreateCITATION: yes
AcceptedWarnings:
- 'Warning: package ''.*'' was built under R version'
- 'Warning: namespace ''.*'' is not available and has been replaced'
AcceptedNotes: madrat:::getSourceFolder
AcceptedNotes:
- madrat:::getSourceFolder
- .* includes the non-default packages.*
allowLinterWarnings: yes
enforceVersionUpdate: yes
skipCoverage: yes
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: 'mrmfa: Input data generation for the REMIND MFA'
version: 1.11.2
date-released: '2026-07-09'
version: 1.12.0
date-released: '2026-07-20'
abstract: The mrmfa packages contains data preprocessing for the REMIND MFA.
authors:
- family-names: Dürrwächter
Expand Down
6 changes: 4 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Type: Package
Package: mrmfa
Title: Input data generation for the REMIND MFA
Version: 1.11.2
Date: 2026-07-09
Version: 1.12.0
Date: 2026-07-20
Authors@R: c(
person("Jakob", "Dürrwächter", , "jakobdu@pik-potsdam.de", role = c("aut", "cre")),
person("Bennet", "Weiss", , "bennet.weiss@pik-potsdam.de", role = "aut"),
Expand All @@ -20,6 +20,7 @@ Depends:
magclass (>= 6.16.1),
mrdrivers (>= 4.0.0),
mrcommonsenergy (>= 0.3.4),
mrindustry (>= 1.2.1),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we need mrindustry now? :)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using 2 sources in the validation mif for plastics that are also used in mrindustry - Stegmann2022 and IEA_Petrochem.

@fbenke-pik fbenke-pik Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important to note that this creates a hierarchy between mrindustry and mrmfa for the first time. Not a problem per-se, but the moment you also need functions from mrmfa in mrindustry, you will need to start moving stuff to mrcommonsenergy.

See also: https://gitlab.pik-potsdam.de/rse/rsewiki/-/wikis/REMIND-mr-package-structure

GDPuc (>= 1.3.0),
Imports:
glue,
Expand All @@ -30,6 +31,7 @@ Imports:
magrittr,
purrr,
quitte,
R.matlab,
readr,
readxl,
rlang,
Expand Down
12 changes: 12 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import(madrat)
import(magclass)
import(mrcommonsenergy)
import(mrdrivers)
import(mrindustry)
importFrom(data.table,first)
importFrom(dplyr,across)
importFrom(dplyr,all_of)
Expand All @@ -24,7 +25,18 @@ importFrom(dplyr,summarise)
importFrom(dplyr,summarize)
importFrom(dplyr,ungroup)
importFrom(magclass,"getComment<-")
importFrom(magclass,"getItems<-")
importFrom(magclass,"getNames<-")
importFrom(magclass,add_dimension)
importFrom(magclass,as.magpie)
importFrom(magclass,collapseNames)
importFrom(magclass,dimSums)
importFrom(magclass,getItems)
importFrom(magclass,getNames)
importFrom(magclass,getYears)
importFrom(magclass,mbind)
importFrom(magclass,mselect)
importFrom(magclass,setNames)
importFrom(magclass,where)
importFrom(magpiesets,findset)
importFrom(magrittr,"%>%")
Expand Down
34 changes: 34 additions & 0 deletions R/calcPlGaoCabrera.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#' Gao & Cabrera-Serrenho 2025 polymer consumption in IAMC variables
#'
#' @description
#' Return total apparent polymer consumption from Gao & Cabrera-Serrenho (2025),
#' "Global Plastic MFA", at ISO3 country level. The 14 polymer groups (plastics,
#' fibres and rubber) are summed into a single total and mapped to the IAMC
#' variable \code{Material Demand|Chemicals|Plastics} in Mt/yr. Note that the
#' years 2020-2021 rely on incomplete trade data.
#'
#' @author Leonie Schweiger
#' @return Total polymer consumption (Mt/yr)
#' @seealso \code{\link{readGaoCabrera2025}}, \code{\link{calcPlPottinger}}
#' @importFrom magclass dimSums getNames<-
calcPlGaoCabrera <- function() {
x <- readSource("GaoCabrera2025")

# sum all 14 polymers into a single total and convert kt -> Mt
x <- dimSums(x, dim = 3) / 1000

getNames(x) <- "Material Demand|Chemicals|Plastics"

return(list(
x = x,
weight = NULL,
unit = "Mt/yr",
description = paste(
"Apparent polymer consumption 1978-2021 from Gao & Cabrera-Serrenho (2025),",
"total over all 14 polymer groups (incl. fibres and rubber), in the IAMC",
"variable Material Demand|Chemicals|Plastics. Years 2020-2021 rely on",
"incomplete trade data."
),
note = "Disaggregated from 8 Gao regions to ISO3 via population weighting"
))
}
38 changes: 38 additions & 0 deletions R/calcPlGeyer.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#' Geyer et al. 2017 global plastics production in IAMC variables
#'
#' @description
#' Return the global annual plastics production time series (1950-2015) from
#' Geyer et al. (2017), doi:10.1126/sciadv.1700782 (Table S1), reported at the
#' global level under the IAMC variables \code{Production|Chemicals|Plastics}
#' and \code{Material Demand|Chemicals|Plastics}, both in Mt/yr. The data are
#' global only and are not disaggregated to countries or regions.
#'
#' @author Leonie Schweiger
#' @return List with a global-only MagPIE object of plastics production (Mt/yr)
#' in IAMC variables and metadata in calcOutput format.
#' @seealso \code{\link{readGeyer}}, \code{\link{calcPlPottinger}},
#' \code{\link{calcPlGaoCabrera}}
#' @importFrom magclass setNames mbind
calcPlGeyer <- function() {
x <- readSource("Geyer", subtype = "Prod_1950-2015", convert = FALSE)

# same global figure reported under both IAMC variables (setNames overwrites
# the single source data-column name with the IAMC variable name)
out <- mbind(
setNames(x, "Production|Chemicals|Plastics"),
setNames(x, "Material Demand|Chemicals|Plastics")
)

return(list(
x = out,
weight = NULL,
unit = "Mt/yr",
description = paste(
"Global annual plastics production 1950-2015 from Geyer et al. (2017),",
"Table S1, reported at the global level under the IAMC variables",
"Production|Chemicals|Plastics and Material Demand|Chemicals|Plastics."
),
isocountries = FALSE,
note = "Global only; no regional disaggregation."
))
}
87 changes: 87 additions & 0 deletions R/calcPlIEA.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#' IEA 2018 global plastics production in IAMC variables
#'
#' @description
#' Return the global annual production of key thermoplastics (1980-2050) from the
#' IEA report "The Future of Petrochemicals" (2018), Figure 4.2 (Reference
#' Technology Scenario), read via \code{readSource("IEA_Petrochem",
#' subtype = "plastics_All")}. The reported total (the source "SUM" series, in Mt)
#' is returned at the global level under the IAMC variables
#' \code{Production|Chemicals|Plastics} and \code{Material Demand|Chemicals|Plastics}.
#' The data are global only and are not disaggregated to countries or regions.
#'
#' @param subtype Character. \code{"total"} (default) returns absolute production
#' and demand in Mt/yr; \code{"perCapita"} returns demand per capita in kg/cap,
#' using Stegmann's own Population variable.
#'
#' @author Leonie Schweiger
#' @return List with a global-only MagPIE object of plastics production (Mt/yr) in
#' IAMC variables.
#' @importFrom magclass setNames mbind getItems getItems<-
calcPlIEA <- function(subtype) {
if (!subtype %in% c("total", "perCapita")) {
stop("Unknown subtype '", subtype, "'. Use 'total' or 'perCapita'.")
}

x <- readSource("IEA_Petrochem", subtype = "plastics_All", convert = FALSE)

# readIEA_Petrochem runs make.names() on the header row, which prefixes the
# numeric year columns with "X" (e.g. 1980 -> X1980). For the plastics subtype
# these become the temporal dimension, so normalise to proper year format.
getYears(x) <- as.integer(sub("^[Xy]", "", getYears(x)))

# get the total production over all polymers
x <- dimSums(x, dim = 3, na.rm = TRUE)

# same global figure reported under both IAMC variables (setNames overwrites the
# single source data-column name with the IAMC variable name)
out <- mbind(
setNames(x, "Production|Chemicals|Plastics"),
setNames(x, "Material Demand|Chemicals|Plastics")
)

if (subtype == "total") {
return(list(
x = out,
weight = NULL,
unit = "Mt/yr",
description = paste(
"Global production of key thermoplastics 1980-2050 from IEA 'The Future of",
"Petrochemicals' (2018), Figure 4.2 (Reference Technology Scenario), reported",
"at the global level under the IAMC variables Production|Chemicals|Plastics",
"and Material Demand|Chemicals|Plastics."
),
isocountries = FALSE,
note = paste(
"Global only; IEA 'key thermoplastics' is a subset of all plastics",
"(excludes thermosets and other polymers)."
)
))
}

popEstimates <- readSource("UN_PopDiv", subtype = "pop", subset = "estimates")
popMedium <- readSource("UN_PopDiv", subtype = "pop", subset = "medium")
getNames(popEstimates) <- NULL
getNames(popMedium) <- NULL
pop <- dimSums(mbind(popEstimates, popMedium), dim = 1)
pop <- pop[, getYears(out), ]

out <- 1000 * out / pop # Mt / million people -> kg/cap
out[!is.finite(out)] <- NA
getItems(out, dim = 3) <- paste0(getItems(out, dim = 3), "|per capita")
getItems(out, dim = 1) <- "GLO"

return(list(
x = out,
weight = pop,
unit = "kg/cap",
description = paste(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I am a big fan of glue:

description = glue::glue(
   "Per-capita Global production of key thermoplastics 1980-2050 from IEA 'The Future of \\
   Petrochemicals' (2018), Figure 4.2 (Reference Technology Scenario), reported \\
   at the global level under the IAMC variables Production|Chemicals|Plastics \\
   and Material Demand|Chemicals|Plastics.; population from UN WPP (estimates + medium)."
)

"Per-capita Global production of key thermoplastics 1980-2050 from IEA 'The Future of",
"Petrochemicals' (2018), Figure 4.2 (Reference Technology Scenario), reported",
"at the global level under the IAMC variables Production|Chemicals|Plastics",
"and Material Demand|Chemicals|Plastics.; population from UN WPP (estimates + medium)."
),
isocountries = FALSE,
note = "Population-weighted; intensive variable aggregated as weighted mean."
))

}
64 changes: 64 additions & 0 deletions R/calcPlOECDProjection.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#' OECD Global Plastics Outlook 2022 projections in IAMC variables
#'
#' @description
#' Return the plastics-use projection 1980-2060) from the OECD Global Plastics Outlook 2022
#' at ISO3 country level, mapped to IAMC variables.
#' \code{subtype = "total"} returns total plastics use as
#' \code{Material Demand|Chemicals|Plastics} (Mt/yr); \code{subtype = "perCapita"}
#' returns \code{Material Demand|Chemicals|Plastics|per capita} (kg/cap), using the
#' OECD population projection where available (2019-2060) and \code{\link{calcCoPopulation}}
#' (SSP2) for the earlier years (1980-2018).
#'
#' @param subtype Character, either "total" (plastics use, Mt/yr, summed on aggregation) or
#' "perCapita" (plastics use per capita, kg/cap, population-weighted mean on aggregation).
#'
#' @author Leonie Schweiger
#' @return List with a MagPIE object of the OECD plastics projection in IAMC variables and
#' metadata.
#' @seealso \code{\link{readOECD_Plastic}}, \code{\link{calcPlGaoCabrera}},
#' \code{\link{calcCoPopulation}}
#' @importFrom magclass setNames getYears getNames<-
calcPlOECDProjection <- function(subtype = "total") {
# plastics use projection (Mt), ISO3, 1980-2060
use <- setNames(readSource("OECD_Plastic", "Use_1980-2060_projection"), NULL)

if (subtype == "total") {
getNames(use) <- "Material Demand|Chemicals|Plastics"
return(list(
x = use,
weight = NULL,
unit = "Mt/yr",
description = paste(
"Plastics use projection 1980-2060 from the OECD Global Plastics Outlook 2022."
),
note = "Disaggregated from 15 OECD-Outlook regions to ISO3 via population weighting."
))
} else if (subtype == "perCapita") {
# OECD population sheet (billion people), ISO3, 2019-2060
popOECD <- setNames(readSource("OECD_Plastic", "Pop_2019-2060_projection"), NULL)
# reference population (calcCoPopulation is in inhabitants -> convert to billion people)
popRef <- setNames(calcOutput("CoPopulation", scenarios = "SSP2", aggregate = FALSE), NULL) / 1e9

years <- getYears(use) # 1980-2060
pop <- popRef[, years, ] # CoPopulation for all years...
overlap <- intersect(years, getYears(popOECD)) # 2019-2060
pop[, overlap, ] <- popOECD[, overlap, ] # ...prefer OECD source pop where available

perCap <- use / pop # Mt / billion people = kg/cap
perCap[is.na(perCap) | is.infinite(perCap)] <- 0
getNames(perCap) <- "Material Demand|Chemicals|Plastics|per capita"
return(list(
x = perCap,
weight = pop,
unit = "kg/cap",
description = paste(
"Per-capita plastics use projection 1980-2060 from the OECD Global Plastics",
"Outlook 2022. OECD population is used for 2019-2060 and ",
"calcCoPopulation (SSP2) for 1980-2018."
),
note = "Population-weighted; intensive variable aggregated as weighted mean."
))
}

stop("Invalid subtype: ", subtype, ". Use 'total' or 'perCapita'.")
}
91 changes: 91 additions & 0 deletions R/calcPlPottinger.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#' Pottinger 2024 plastics material flows in IAMC variables
#'
#' @description
#' Return the plastics material-flow data from Pottinger et al. (2024) for a
#' specified scenario (Business-as-Usual or policy variants), at ISO3 country
#' level, with the source flow columns renamed to a subset of IAMC variables.
#' All flows are in Mt/yr.
#'
#' @param subtype Character, scenario to extract (e.g., "businessAsUsual" for BAU).
#' Must match a scenario name encoded in the data dimension from readPottinger2024.
#' @param perCapita Logical. If \code{FALSE} (default), return absolute flows in
#' Mt/yr. If \code{TRUE}, return per-capita flows in kg/cap, using the same UN
#' World Population Prospects population as \code{\link{convertPottinger2024}}.
#'
#' @author Leonie Schweiger
#' @return List with a MagPIE object of plastics flows (Mt/yr, or kg/cap if
#' \code{perCapita = TRUE}) in IAMC variables and metadata in calcOutput format.
#' @seealso \code{\link{readPottinger2024}}
#' @importFrom magclass getItems getItems<- mbind getYears getNames<-
calcPlPottinger <- function(subtype = "businessAsUsual", perCapita = FALSE) {
x <- readSource("Pottinger2024")
scenarios <- getNames(x, dim=1)
variables <- getNames(x, dim=2)

if (subtype == "all") {
x <- x
} else if (!(subtype %in% scenarios)) {
stop("Scenario '", subtype, "' not found in Pottinger2024 data. ",
"Available scenarios: ", paste(scenarios, collapse = ", "))
} else {
x <- x[, , subtype]
}

# map raw source flow columns to IAMC variables
iamc <- c(
totalConsumptionMt = "Material Demand|Chemicals|Plastics",
primaryProductionMt = "Production|Chemicals|Plastics|Primary",
secondaryProductionMt = "Production|Chemicals|Plastics|Secondary"
)

# identify which of the mapped variables are present in this scenario
keep_idx <- which(variables %in% names(iamc))
variables_kept <- variables[keep_idx]

if (length(keep_idx) == 0) {
stop("No mapped variables found for scenario '", subtype, "' in Pottinger2024. ",
"Expected one or more of: ", paste(names(iamc), collapse = ", "))
}

# subset to keep only mapped variables
x <- x[, , variables_kept]
new_names <- iamc[variables_kept]
getItems(x, dim = 3.2) <- as.vector(new_names)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, toolAggregate has been fixed to not blow up dimensions with more than one subdimension, so this should now work as well and yield identical results

  map <- data.frame(
    from = c("totalConsumptionMt", "primaryProductionMt", "secondaryProductionMt"),
    to =  c("Material Demand|Chemicals|Plastics", "Production|Chemicals|Plastics|Primary", "Production|Chemicals|Plastics|Secondary")
  )

  x <- toolAggregate(x, dim = 3.2, map, partrel = TRUE, verbosity = 2)


if (!perCapita) {
return(list(
x = x,
weight = NULL,
unit = "Mt/yr",
description = paste(
"Plastics material-flow pathway 2011-2050 from Pottinger et al. (2024),",
"scenario:", subtype, "in IAMC variables"
),
note = "Disaggregated from 4 Pottinger regions to ISO3 via population weighting"
))
}

# per-capita: same UN World Population Prospects population as convertPottinger2024
# (estimates through 2021 + medium variant from 2022), in millions of people
popEstimates <- readSource("UN_PopDiv", subtype = "pop", subset = "estimates")
popMedium <- readSource("UN_PopDiv", subtype = "pop", subset = "medium")
getNames(popEstimates) <- NULL
getNames(popMedium) <- NULL
pop <- mbind(popEstimates, popMedium)
pop <- pop[getItems(x, dim = 1), getYears(x), ] # ISO3 countries & Pottinger years

x <- 1000 * x / pop # Mt / million people -> kg/cap
x[!is.finite(x)] <- NA
getItems(x, dim = 3.2) <- paste0(as.vector(new_names), "|per capita")

return(list(
x = x,
weight = pop,
unit = "kg/cap",
description = paste(
"Per-capita plastics material-flow pathway 2011-2050 from Pottinger et al. (2024),",
"scenario:", subtype, "in IAMC variables; population from UN WPP (estimates + medium)."
),
note = "Population-weighted; intensive variable aggregated as weighted mean."
))
}
Loading
Loading