Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Peatland rewetting automatically considered during SEALS downscaling #759

Merged
merged 6 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]

### changed
-
- **scripts** peatland rewetting now automatically considered in `extra/runSEALSallocation.R`

### added
-
Expand Down
18 changes: 9 additions & 9 deletions config/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ cfg$model <- "main.gms" #def = "main.gms"
cfg$input <- c(regional = "rev4.116_h12_magpie.tgz",
cellular = "rev4.116_h12_fd712c0b_cellularmagpie_c200_MRI-ESM2-0-ssp370_lpjml-8e6c5eb1.tgz",
validation = "rev4.116_h12_validation.tgz",
additional = "additional_data_rev4.59.tgz",
additional = "additional_data_rev4.60.tgz",
calibration = "calibration_H12_27Sep24.tgz")

# NOTE: It is recommended to recalibrate the model when changing cellular input data
Expand Down Expand Up @@ -612,7 +612,7 @@ cfg$gms$s21_trade_tariff_startyear <- 2025
# * end year of fadeout if s21_trade_tariff_fadeout = 1 # def = 2050
cfg$gms$s21_trade_tariff_targetyear <- 2050

# * Minimum trade margin for forestry products (USD17MER per tDM)
# * Minimum trade margin for forestry products (USD17MER per tDM)
# * (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

Expand Down Expand Up @@ -760,8 +760,8 @@ cfg$gms$s29_treecover_scenario_start <- 2025 # def = 2025
cfg$gms$s29_treecover_scenario_target <- 2050 # def = 2050
# * Penalty for violation of treecover target before scenario start (USD17MER per ha)
# * (inflated from default originally in USD05 using USD05 --> USD17 inflation rate:1.23)
cfg$gms$s29_treecover_penalty_before <- 0 # def = 0
# * Penalty for violation of treecover target after scenario start (USD17MER per ha)
cfg$gms$s29_treecover_penalty_before <- 0 # def = 0
# * Penalty for violation of treecover target after scenario start (USD17MER per ha)
# * (inflated from default originally in USD05 using USD05 --> USD17 inflation rate: 1.23)
cfg$gms$s29_treecover_penalty <- 6150 # def = 5000 * 1.23
# * Tree cover establishment cost (USD17MER per ha)
Expand Down Expand Up @@ -1733,13 +1733,13 @@ cfg$gms$policy_countries58 <- all_iso_countries
cfg$gms$s58_rewetting_exo <- 0 # def = 0
# * Switch for exogenous peatland rewetting for all other countries (0=off, 1=on)
cfg$gms$s58_rewetting_exo_noselect <- 0 # def = 0
# * The following default values for exogenous peatland rewetting are based on the
# * The following default values for exogenous peatland rewetting are based on the
# * Nature Restoration Law (NRL): 30 % by 2030, 40% by 2040, 50% by 2050
# * Start year for exogenous peatland rewetting
cfg$gms$s58_rewet_exo_start_year <- 2030 # def = 2030
# * Target year for exogenous peatland rewetting
cfg$gms$s58_rewet_exo_target_year <- 2050 # def = 2050
# * Start value for exogenous peatland rewetting as share of drained peatland in reference period
# * Start value for exogenous peatland rewetting as share of drained peatland in reference period
cfg$gms$s58_rewet_exo_start_value <- 0.3 # def = 0.3
# * Target value for exogenous peatland rewetting as share of drained peatland in reference period
cfg$gms$s58_rewet_exo_target_value <- 0.5 # def = 0.5
Expand Down Expand Up @@ -1907,9 +1907,9 @@ cfg$gms$c60_biodem_level <- 1 # def = 1
cfg$gms$s60_2ndgen_bioenergy_dem_min <- 1 # def = 1

# * t DM-based first generation bioenergy subsidy (USD17MER per ton)
# * The subsidy can simulate a perfectly elastic demand for bioenergy from the energy sector and should be used as a
# * default floor price that avoids the wastage of ethanal or oils in case that the demand for byproducts
# * (oilcake and brewers grains) exceeds the demand for these secondary products. As such, it also avoids unrealistic
# * The subsidy can simulate a perfectly elastic demand for bioenergy from the energy sector and should be used as a
# * default floor price that avoids the wastage of ethanal or oils in case that the demand for byproducts
# * (oilcake and brewers grains) exceeds the demand for these secondary products. As such, it also avoids unrealistic
# * price fluctuations connected to the inelastic demand for couple products.
# * (1stgen_priced_dec18): c60_bioenergy_subsidy is applied constant over historic and model horizon, c60_bioenergy_subsidy_fix_SSP2 has no effect
# * (1st2ndgen_priced_feb24): c60_bioenergy_subsidy_fix_SSP2 is applied constant to historic time steps (up until sm_fix_SSP2).
Expand Down
128 changes: 104 additions & 24 deletions scripts/output/extra/runSEALSallocation.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# 1.00: first working version

library(gms)
library(gdx)
library(gdx2)
library(magpie4)
library(filelock)

Expand Down Expand Up @@ -63,9 +63,10 @@ if (length(cfg$seals_years) != 0) {
}

# Restructure data to conform to SEALS
sealsInput <- paste0("cell.land_0.5_SEALS_", title, ".nc")
reportLandUseForSEALS(
magCellLand = "cell.land_0.5_share.mz",
outFile = paste0("cell.land_0.5_SEALS_", title, ".nc"),
outFile = sealsInput,
dir = outputdir, selectyears = rep_years
)

Expand Down Expand Up @@ -108,11 +109,13 @@ Sys.chmod(iniLock, mode = "0664")
# Prepare SEALS start script
# --------------------------------

.setupSEALSrun <- function(title, dir, dirProject, dirSEALS, dirBaseFiles) {
.setupSEALSrun <- function(cfg, sealsInput, dir, dirProject, dirSEALS, dirBaseFiles) {
if (!dir.exists(file.path(dirProject, "scripts"))) {
dir.create(file.path(dirProject, "scripts"), recursive = TRUE)
}

title <- cfg$title

file.copy(
from = list.files(file.path(dirSEALS, "seals"), full.names = TRUE),
to = file.path(dirProject, "scripts"),
Expand All @@ -124,11 +127,94 @@ Sys.chmod(iniLock, mode = "0664")
dir.create(file.path(dirProject, "inputs"), recursive = TRUE)
}

file.copy(
from = file.path(dir, paste0("seals_scenario_config_", title, ".csv")),
to = file.path(dirProject, "inputs", paste0("seals_scenario_config_", title, ".csv")),
overwrite = TRUE
rcp <- unlist(strsplit(cfg$input["cellular"], "_"))[6]
rcp <- paste0("rcp", substr(rcp, nchar(rcp) - 1, nchar(rcp)))

ssp <- tolower(cfg$gms$c09_pop_scenario)

if (length(cfg$seals_years) != 0) {
sealsYears <- cfg$seals_years[cfg$seals_years > 2020]
sealsYears <- paste(sealsYears, collapse = " ")
} else {
sealsYears <- "2050"
}

scenarioType <- ifelse(grepl("default|bau|ssp\\d-ref", tolower(title)), "bau", "policy")

if (cfg$gms$c22_protect_scenario == "none") {
consv <- cfg$gms$c22_base_protect
} else {
consv <- cfg$gms$c22_protect_scenario
}

### Modify SEALS model coefficients based on scenario settings

message("Updating SEALS model coefficients based on scenario settings")

sealsCoeff <- c(
"input/seals_global_coefficients.csv",
"../input/seals_global_coefficients.csv",
"../../input/seals_global_coefficients.csv"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
sealsCoeff <- c(
"input/seals_global_coefficients.csv",
"../input/seals_global_coefficients.csv",
"../../input/seals_global_coefficients.csv"
)
sealsCoeff <- paste0(c("./", "../", "../../"), "input/seals_global_coefficients.csv")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks Pascal for these simplifications! I've reworked the parts of the code. Please double check.

sealsCoeff <- suppressWarnings(sealsCoeff[min(which(file.exists(sealsCoeff)))])
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems rather hacky, is there no way of knowing where the file will actually be?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This approach is pretty common in post-processing functions mostly in the magpie4 library, from which I have transferred part of the code. This makes the code more stable and less susceptible depending on which relative directory the code may be run.

Would you have an alternative suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

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

My suggestion would be to not run the code from different relative directories / setup up the whole system in a way such that that is not necessary. Not something that can be solved in this script though.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a bit nicer this way:

Suggested change
sealsCoeff <- suppressWarnings(sealsCoeff[min(which(file.exists(sealsCoeff)))])
sealsCoeff <- Find(file.exists, sealsCoeff)

This returns NULL if no file exists, so would need to change line 160 to !is.null

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest the same for seals config below as well

if (!is.na(sealsCoeff)) {
sealsCoeff <- read.csv(sealsCoeff)
consvRow <- which(sealsCoeff[, "spatial_regressor_name"] == "land_conservation")
sealsCoeff[consvRow, "data_location"] <- sub(
"WDPA", consv, sealsCoeff[consvRow, "data_location"]
)

peatlandPrice <- readGDX(file.path(dir, "fulldata.gdx"), "im_pollutant_prices")
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to use a different criterion for activating peatlands in SEALS.
We now also have to option for external peatland rewetting scenarios.
Therefore, I suggest to use rewetted peatland area as criterion, as a share of total peatland area.
dimSums(PeatlandArea(gdx)[,,"rewet"],dim=1)/dimSums(PeatlandArea(gdx),dim=c(1,3))>0.01

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for spotting this and the suggestion! I've changed the code based on your suggestion.

if (any(peatlandPrice[, as.numeric(sealsYears), "co2_c.peatland"] > 0)) {
peatRow <- which(sealsCoeff[, "spatial_regressor_name"] == "peatland_rewetting")
# SEALS rewetting coefficient
rewetCoeff <- 10000
# disincentivise agricultural expansion
sealsCoeff[peatRow, c("cropland", "grassland")] <- rewetCoeff
# peatland rewetting incentive
sealsCoeff[peatRow, c("forest", "othernat")] <- -rewetCoeff
}

sealsCoeffPath <- file.path(
dirProject, "inputs",
paste0("seals_global_coefficients_", title, ".csv")
)

write.csv(sealsCoeff, sealsCoeffPath,
row.names = FALSE, na = ""
)
} else {
stop("Could not find seals_global_coefficients.csv file")
}


### Create SEALS scenario definitions CSV

message("Creating SEALS scenario definitions CSV")

sealsConfig <- c(
"input/seals_scenario_config.csv",
"../input/seals_scenario_config.csv",
"../../input/seals_scenario_config.csv"
)
sealsConfig <- suppressWarnings(sealsConfig[min(which(file.exists(sealsConfig)))])
if (!is.na(sealsConfig)) {
sealsConfig <- read.csv(sealsConfig)
sealsConfig[nrow(sealsConfig), "scenario_label"] <- title
sealsConfig[nrow(sealsConfig), "scenario_type"] <- scenarioType
sealsConfig[nrow(sealsConfig), "exogenous_label"] <- ssp
sealsConfig[nrow(sealsConfig), "climate_label"] <- rcp
sealsConfig[nrow(sealsConfig), "counterfactual_label"] <- title
sealsConfig[nrow(sealsConfig), "comparison_counterfactual_labels"] <- ifelse(scenarioType == "bau", "", "bau")
sealsConfig[, "coarse_projections_input_path"] <- normalizePath(file.path(dir, sealsInput))
sealsConfig[nrow(sealsConfig), "years"] <- sealsYears
sealsConfig[nrow(sealsConfig), "calibration_parameters_source"] <- normalizePath(sealsCoeffPath)
write.csv(sealsConfig, file.path(dirProject, "inputs", paste0("seals_scenario_config_", title, ".csv")),
row.names = FALSE, na = ""
)
} else {
stop("Could not find seals_scenario_config.csv file template")
}

main <- readLines(file.path(dirProject, "scripts", "run_test_standard.py"))

Expand Down Expand Up @@ -200,19 +286,21 @@ Sys.chmod(iniLock, mode = "0664")
if (!is.null(lockOn)) {
sealsLock <- file.path(dirProject, "seals.lock")

.setupSEALSrun(
cfg = cfg,
sealsInput = sealsInput,
dir = outputdir,
dirProject = dirProject,
dirSEALS = dirSEALS,
dirBaseFiles = dirBaseFiles
)

if (!file.exists(sealsLock) || file.size(sealsLock) == 0) {
message(paste(
"Starting SEALS allocation with input data creation.\n",
"Stitched SEALS allocation outputs will be written to",
"'./output/seals/intermediate/stitched_lulc_simplified_scenarios'"
))
.setupSEALSrun(
title = title,
dir = outputdir,
dirProject = dirProject,
dirSEALS = dirSEALS,
dirBaseFiles = dirBaseFiles
)

id <- .submitSEALS(
title = title,
Expand All @@ -225,22 +313,14 @@ if (!is.null(lockOn)) {

writeLines(id, sealsLock)
} else {
id <- readLines(sealsLock)

message(paste(
"Starting SEALS allocation using existing input data.\n",
"Stitched SEALS allocation outputs will be written to",
"'./output/seals/intermediate/stitched_lulc_simplified_scenarios'"
))

id <- readLines(sealsLock)

.setupSEALSrun(
title = title,
dir = outputdir,
dirProject = dirProject,
dirSEALS = dirSEALS,
dirBaseFiles = dirBaseFiles
)

.submitSEALS(
title = title,
dirProject = dirProject,
Expand Down