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

Start script 'healthy landscapes paper' and output script for automatic submission of SEALS runs #721

Merged
merged 13 commits into from
Sep 20, 2024
Merged
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **config** additional data update additional_data_rev4.53.tgz
- **29_cropland** added option for linear and sigmoidal faders
- **scripts** output/extra/highres.R use default 13_tc realization
- **scripts** `.nc` files are no longer created by default after disaggregation


### added
Expand All @@ -34,9 +35,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **cropland** added option for discarding initial treecover on cropland
- **script** added output script for conversion of validation.mif file into validation.rds
- **script** for downscaling to 0.25 deg using LUH2v2h as reference via mrdownscale
- **config** added `scenario_config_year_fix.csv` for choosing until when parameters are fixed to SSP2 values
- **scripts** added start script for 'Healthly Landscapes' paper `paper_healthyLscps.R`
- **scripts** added script for automatic submission of SEALS allocation runs `./extra/runSEALSallocation.R`

### removed
-


### fixed
- **scripts** fixing an error in start.R and output.R which occurred if more than one slurm job was submitted at the same time.
Expand All @@ -50,7 +54,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### changed
- **29_ageclass** module 29_ageclass has been renamed to 28_ageclass to make space for `29_cropland` just before `30_croparea`
- **30_crop** module `30_crop` renamed to `30_croparea`, which now only accounts for crop area.
- **30_crop** Semi-Natural Vegetation (SNV) implementation has been moved from `30_crop` to `29_cropland`
- **30_crop** Semi-Natural Vegetation (SNV) implementation has been moved from `30_crop` to `29_cropland`
- **30_crop** the previous `30_crop/endo_apr21` realization has been moved to `30_croparea/simple_apr24`
- **30_crop** the two realizations `penalty_apr22` and `rotation_apr22` have been merged into a single `30_croparea/detail_apr24` realization
- **default.cfg** update additional data to rev4.51
Expand Down
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Imports:
m4fsdp,
madrat,
magclass (>= 6.14.0),
magpie4 (>= 2.11.0),
magpie4 (>= 2.12.0),
MagpieNCGains,
magpiesets,
mip,
Expand Down
21 changes: 12 additions & 9 deletions config/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ cfg$gms$kfo_rd <- "livst_rum" #def = livst_rum

# * Switch for supplemental fat needed as ingredient for scp-based meat alternatives
# * options: 0 (=off), 1 (=on)
cfg$gms$s15_scp_supplement_fat_meat <- 0 # def = 0
cfg$gms$s15_scp_supplement_fat_meat <- 0 # def = 0

# * Convergence of livestock food calorie supply towards a kcal/cap/day target with or w/o substitution.
# * The functional form and the start and target years of the food substitution can be specified below.
Expand Down Expand Up @@ -695,7 +695,7 @@ cfg$gms$ageclass <- "feb21" # def = feb21
# ***--------------------- 29_cropland -----------------------------------
# * Cropland is defined as the sum of croparea, fallow land and tree cover
# * Croparea is provided by 30_crop.
# * Fallow land and tree cover are defined by 29_cropland,
# * Fallow land and tree cover are defined by 29_cropland,
# * (simple_apr24): Fallow land and tree cover on cropland are fixed to zero
# * (detail_apr24): Fallow land and tree cover based on rules or incentives
# NOTE: It is recommended to recalibrate the model when changing this setting!
Expand Down Expand Up @@ -737,7 +737,7 @@ cfg$gms$s29_snv_scenario_target <- 2050 # def = 2050
# * plausible options: "secdforest, forestry, past, other",
# * "secdforest, other",
# * "secdforest, past, other" etc.
cfg$gms$land_snv <- "secdforest, forestry, past, other" #def = "secdforest, forestry, past, other"
cfg$gms$land_snv <- "secdforest, other" #def = "secdforest, other"
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add to the changelog that the default setting for the SVN policy has changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated the changelog. Thanks for spotting this


# *** Options only available for `detail_apr24` realization ***

Expand All @@ -755,7 +755,7 @@ cfg$gms$s29_treecover_map <- 0 # def = 0
# s29_treecover_target_noselect applies to all other countries.
cfg$gms$s29_treecover_target <- 0 # def = 0
cfg$gms$s29_treecover_target_noselect <- 0 # def = 0
# * Avoid loss of existing treecover (1=yes 0=no).
# * Avoid loss of existing treecover (1=yes 0=no).
# * If set to 1, `s29_treecover_target` will be adjusted based existing treecover area.
cfg$gms$s29_treecover_keep <- 0 # def = 0
# * Maximum share of treecover on total cropland (1)
Expand Down Expand Up @@ -808,12 +808,12 @@ cfg$gms$policy_countries30 <- all_iso_countries
## Agroforestry settings for bioenergy trees
# * Sigmoid fader for minimum area share of bioenergy trees (betr) on total cropland at cluster level
# * Minimum area share of bioenergy trees on total cropland in start year
# Note: s30_betr_start applies to countries selected in policy_countries30,
# Note: s30_betr_start applies to countries selected in policy_countries30,
# s30_betr_start_noselect applies to all other countries.
cfg$gms$s30_betr_start <- 0 # def = 0
cfg$gms$s30_betr_start_noselect <- 0 # def = 0
# * Minimum area share of bioenergy trees on total cropland in target year
# Note: s30_betr_target applies to countries selected in policy_countries30,
# Note: s30_betr_target applies to countries selected in policy_countries30,
# s30_betr_target_noselect applies to all other countries.
cfg$gms$s30_betr_target <- 0 # def = 0
cfg$gms$s30_betr_target_noselect <- 0 # def = 0
Expand Down Expand Up @@ -841,14 +841,14 @@ cfg$gms$s30_implementation <- 1 # def = 1
# * Rotation rules:
# * min (minimal constraints), default (best guess), good (good practice),
# * good_20div (good practice - 20% for other crops), setaside (default plus fallow),
# * legumes (minimum share of legumes), sixfoldrotation (crops can only repeat after 6 years),
# * legumes (minimum share of legumes), sixfoldrotation (crops can only repeat after 6 years),
# * agroecology (mix of previous scenarios), FSEC (similar to agroecology)
# * betr0 (minimum share of short rotation agroforestry trees), betr10, betr20, betr25, betr30, betr40, betr50.
cfg$gms$c30_rotation_rules <- "default" # def = "default"

# * Rotation incentives:
# * none (no incentives), default (best guess),
# * legumes (increased incentives for legumes), agroecology (mix),
# * none (no incentives), default (best guess),
# * legumes (increased incentives for legumes), agroecology (mix),
# * betr500 and betr1000 (incentives for short rotation agroforestry trees)
cfg$gms$c30_rotation_incentives <- "none" # def = "none"

Expand Down Expand Up @@ -2072,6 +2072,9 @@ cfg$gms$s80_secondsolve <- 0 # def = 0
# bjoernAR6_C_SSP2-NPi.mif, bjoernAR6_C_SSP2-PkBudg900.mif
cfg$magicc_emis_scen <- "bjoernAR6_C_SSP2-NDC.mif"

# Years in which SEALS downscaling is applied
cfg$seals_years <- c(2020, 2050)

# Decide whether the runs should be run sequentially (TRUE),
# or in parallel (FALSE)
# NA means that this decision is taken automatically
Expand Down
16 changes: 16 additions & 0 deletions config/projects/scenario_config_year_fix.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
;fix_2020;fix_2025
pvjeetze marked this conversation as resolved.
Show resolved Hide resolved
gms$sm_fix_SSP2;2020;2025
gms$sm_fix_cc;2020;2025
gms$s15_food_substitution_start;2020;2025
gms$s15_exo_foodscen_start;2020;2025
gms$s21_trade_tariff_startyear;2020;2025
gms$s22_conservation_start;2020;2025
gms$s29_snv_scenario_start;2020;2025
gms$s29_treecover_scenario_start;2020;2025
gms$s29_fallow_scenario_start;2020;2025
gms$s30_betr_scenario_start;2020;2025
gms$s30_rotation_scenario_start;2020;2025
gms$s38_startyear_labor_substitution;2020;2025
gms$s42_efp_startyear;2020;2025
gms$s44_start_year;2020;2025
gms$s70_feed_substitution_start;2020;2025
1 change: 0 additions & 1 deletion scripts/output/extra/disaggregation.R
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ if (length(map_file) > 1) {
base::message(message)
x <- .fixCoords(x)
write.magpie(x, file, comment = comment)
write.magpie(x, sub(".mz", ".nc", file), comment = comment)
}

.dissagcrop <- function(gdx, land_hr, map_file) {
Expand Down
231 changes: 231 additions & 0 deletions scripts/output/extra/runSEALSallocation.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# | (C) 2008-2024 Potsdam Institute for Climate Impact Research (PIK)
# | authors, and contributors see CITATION.cff file. This file is part
# | of MAgPIE and licensed under AGPL-3.0-or-later. Under Section 7 of
# | AGPL-3.0, you are granted additional permissions described in the
# | MAgPIE License Exception, version 1.0 (see LICENSE file).
# | Contact: [email protected]

# --------------------------------------------------------------
# description: Starts SEALS allocation run based on gridded MAgPIE land cover projections (SEALS)
pvjeetze marked this conversation as resolved.
Show resolved Hide resolved
# comparison script: FALSE
# ---------------------------------------------------------------

# Version 1.00 - Patrick v. Jeetze, Pascal Sauer
# 1.00: first working version

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

message("Initialising SEALS allocation run")

############################# BASIC CONFIGURATION #######################################
if (!exists("source_include")) {
title <- NULL
outputdir <- NULL

# Define arguments that can be read from command line
readArgs("outputdir", "title")
}
#########################################################################################

# ========================
# User settings
# ========================

### SEALS python environment name
# see https://justinandrewjohnson.com/earth_economy_devstack/installation.html
# for instructions on how to set up a python environment for SEALS
sealsEnv <- "seals_dev"

### Path to miniforge installation
# For instructions on how to install miniforge see https://github.com/conda-forge/miniforge
miniforgePath <- "/home/vjeetze/miniforge3/bin/activate"
Copy link
Contributor

Choose a reason for hiding this comment

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

Paths into home directories are not ideal, I get permission denied, and even if you give permission this only works as long as your home folder exists.

Copy link
Contributor

Choose a reason for hiding this comment

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

How do you want this script to be used by others, should they install miniforge themselves (into their home folder) and then modify the script here? Or can we setup a shared miniforge path in /p/projects/rd3mod maybe?

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 goes back to the whole discussion whether miniforge should be available to all (e.g. via the piam module or else). At the moment I could only install it into my home directory. This may be fine for the time being and if any users want to use the script they can install it in their home directory and change the path.

I don't expect this script to be used by anyone besides me at the moment. I want this to be part of the release in the current form mainly for reasons of documentation for a paper. However, the script is also fully functional, if the user settings are modified based on user specific installations of miniforge and SEALS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've adapted the script based on our bilateral discussion. Please have a look whether you are fine with these changes.


### Path to SEALS base input file directory
dirBaseFiles <- "/p/projects/magpie/users/vjeetze/seals/files"

### Path to SEALS code base
dirSEALS <- "/p/projects/magpie/users/vjeetze/seals/files/seals/seals_dev"
pvjeetze marked this conversation as resolved.
Show resolved Hide resolved


# ========================
# Prepare MAgPIE output
# ========================

message("Script started for output directory: ", outputdir)

cfg <- gms::loadConfig(file.path(outputdir, "config.yml"))
title <- cfg$title

if (length(cfg$seals_years) != 0) {
rep_years <- cfg$seals_years[cfg$seals_years > 2020]
rep_years <- c(2020, rep_years)
} else {
rep_years <- seq(2020, 2050, 5)
}

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


# ========================
# Setup SEALS run
# ========================

# --------------------------------
# Prepare SEALS start script
# --------------------------------

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

file.copy(
from = list.files(file.path(dirSEALS, "seals"), full.names = TRUE),
to = file.path(dirProject, "scripts"),
overwrite = TRUE,
recursive = TRUE
)

if (!dir.exists(file.path(dirProject, "inputs"))) {
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
)

main <- readLines(file.path(dirProject, "scripts/run_test_standard.py"))
pvjeetze marked this conversation as resolved.
Show resolved Hide resolved

main[min(which(grepl(" p.user_dir =", main)))] <- paste0(" p.user_dir = \'", dirBaseFiles, "\'")
main[min(which(grepl(" p.extra_dirs", main)))] <- paste0(" p.extra_dirs = '.'")
main[min(which(grepl(" p.project_name =", main)))] <- paste0(" p.project_name = \'", title, "\'")
main[min(which(grepl(" p.project_dir =", main)))] <- paste0(
" p.project_dir = \'", normalizePath(dirProject), "\'"
)
main[min(which(grepl("hb.pretty_time()", main)))] <- " "
main[min(which(grepl(" p.base_data_dir =", main)))] <- paste0(
" p.base_data_dir = \'", dirBaseFiles, "/base_data\'"
)
main[min(which(grepl(" p.scenario_definitions_filename =", main)))] <- paste0(
" p.scenario_definitions_filename = \'", paste0("seals_scenario_config_", title, ".csv"), "\'"
)

writeLines(main, file.path(dirProject, "scripts", paste0("run_seals_", title, ".py")))


if (!dir.exists(file.path(dirProject, "run_submit"))) {
dir.create(file.path(dirProject, "run_submit"), recursive = TRUE)
}
}

# --------------------------------
# Submit run
# --------------------------------

.submitSEALS <- function(title, dirProject, miniforgePath, sealsEnv, qos = "short",
slurmID = FALSE, dependsID = NULL) {
submitFile <- file.path(dirProject, "run_submit", paste0("submit_seals_", title, ".sh"))

submit <- c(
"#!/bin/bash", "\n",
paste0("#SBATCH --qos=", qos),
ifelse(qos %in% c("priority", "standby"), "#SBATCH --partition=priority", "#SBATCH --partition=standard"),
pvjeetze marked this conversation as resolved.
Show resolved Hide resolved
"#SBATCH --job-name=seals_allocation",
paste0("#SBATCH --chdir=", normalizePath(file.path(dirProject, "scripts"))),
"#SBATCH --output=outfile_%j.out",
"#SBATCH --error=outfile_%j.err",
"#SBATCH --mail-type=END,FAIL",
"#SBATCH --time=3:00:00",
"#SBATCH --nodes=1",
"#SBATCH --ntasks=1",
ifelse(!is.null(dependsID), paste0(
"#SBATCH --dependency=afterok:", dependsID,
"\n#SBATCH --kill-on-invalid-dep=yes"
),
"#SBATCH --dependency=singleton"
), "\n",
ifelse(qos == "priority", "#SBATCH --cpus-per-task=64", "#SBATCH --cpus-per-task=128"), "\n",
paste("source", miniforgePath),
paste("conda activate", sealsEnv), "\n",
paste("python", paste0("run_seals_", title, ".py"))
)
writeLines(submit, submitFile)

id <- system(paste("sbatch --parsable", submitFile), intern = TRUE)
if (slurmID) {
return(id)
}
}

# create output directory
dirProject <- "./output/seals"

if (!dir.exists(file.path(dirProject))) {
dir.create(file.path(dirProject), recursive = TRUE)
}

iniLock <- file.path(dirProject, ".lock")
lockOn <- filelock::lock(iniLock, exclusive = TRUE, timeout = Inf)
Sys.chmod(iniLock, mode = "0664")

# --------------------------------
# Run SEALS allocation
# --------------------------------

if (!is.null(lockOn)) {
sealsLock <- file.path(dirProject, "seals.lock")

if (!file.exists(sealsLock) || file.size(sealsLock) == 0) {
message("Starting SEALS allocation with input data creation.")
.setupSEALSrun(
title = title,
dir = outputdir,
dirProject = dirProject,
dirSEALS = dirSEALS,
dirBaseFiles = dirBaseFiles
)

id <- .submitSEALS(
title = title,
dirProject = dirProject,
miniforgePath = miniforgePath,
sealsEnv = sealsEnv,
qos = "short",
slurmID = TRUE
)

writeLines(id, sealsLock)
} else {
message("Starting SEALS allocation using existing input data.")
id <- readLines(sealsLock)

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

.submitSEALS(
title = title,
dirProject = dirProject,
miniforgePath = miniforgePath,
sealsEnv = sealsEnv,
qos = "short",
slurmID = FALSE,
dependsID = id
)
}
unlink(iniLock)
}
2 changes: 1 addition & 1 deletion scripts/start/projects/GENIE_0_default.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# | (C) 2008-2021 Potsdam Institute for Climate Impact Research (PIK)
# | (C) 2008-2024 Potsdam Institute for Climate Impact Research (PIK)
# | authors, and contributors see CITATION.cff file. This file is part
# | of MAgPIE and licensed under AGPL-3.0-or-later. Under Section 7 of
# | AGPL-3.0, you are granted additional permissions described in the
Expand Down
4 changes: 2 additions & 2 deletions scripts/start/projects/GENIE_1_tau-export.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# | (C) 2008-2021 Potsdam Institute for Climate Impact Research (PIK)
# | (C) 2008-2024 Potsdam Institute for Climate Impact Research (PIK)
# | authors, and contributors see CITATION.cff file. This file is part
# | of MAgPIE and licensed under AGPL-3.0-or-later. Under Section 7 of
# | AGPL-3.0, you are granted additional permissions described in the
Expand Down Expand Up @@ -52,7 +52,7 @@ cfg$info$flag <- identifierFlag
cfg$results_folder <- paste0("output/", identifierFlag, "/:title:")

cfg$gms$c44_bii_decrease <- 0
cfg$gms$c22_protect_scenario <- "BH"
cfg$gms$c22_protect_scenario <- "BH"

cfg$gms$s60_2ndgen_bioenergy_dem_min_post_fix <- 0
cfg$gms$c60_bioenergy_subsidy <- 0
Expand Down
Loading
Loading