diff options
Diffstat (limited to 'R/PELMO_runs.R')
-rw-r--r-- | R/PELMO_runs.R | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/R/PELMO_runs.R b/R/PELMO_runs.R new file mode 100644 index 0000000..7430b40 --- /dev/null +++ b/R/PELMO_runs.R @@ -0,0 +1,296 @@ +#' Set up runs for FOCUS PELMO +#' +#' Per default, the runs are also executed with FOCUS PELMO, and the results are processed +#' and returned. +#' +#' @param runs A list of lists. Each inner lists has an element named 'psm' +#' that holds the psm string, and elements named using three letter crop acronyms, +#' as used in \code{\link{FOCUS_PELMO_crops}}, +#' that hold character vectors of three letter scenario acronyms +#' as used in \code{\link{FOCUS_GW_scenarios_2012}}. +#' @param psm_dir The directory where the psm files are located +#' @param version The FOCUS PELMO version +#' @param PELMO_base Where the FOCUS PELMO installation is located +#' @param execute Should PELMO be executed directly? +#' @param cores The number of cores to execute PELMO runs in parallel +#' @param evaluate Should the results be returned? +#' @param overwrite Should an existing run directories be overwritten +#' @export +PELMO_runs <- function(runs, psm_dir = ".", version = "5.5.3", PELMO_base = "auto", + execute = TRUE, cores = getOption("mc.cores", 2L), + evaluate = TRUE, overwrite = FALSE) +{ + if (PELMO_base[1] == "auto") { + PELMO_base = file.path(system.file(package = "PELMO.installeR"), + paste0("FOCUSPELMO.", gsub("\\.", "", version))) + } + PELMO_exe = list.files(PELMO_base, "^pelmo.*.exe", full.names = TRUE) + if (length(PELMO_exe) == 0) { + stop("Could not find PELMO executable. Did you run PELMO.installeR::install_PELMO()?") + } + + run_list <- create_run_list(runs, psm_dir = psm_dir, check_psm_files = TRUE) + + setup_run <- function(x) { + psm <- x$psm + crop <- x$crop + scenario <- x$scenario + + location_code <- FOCUS_PELMO_location_codes[scenario] + + run_dir <- file.path(PELMO_base, "FOCUS", PELMO_path(psm, crop, scenario)) + + if (dir.exists(run_dir)) { + if (overwrite) { + unlink(run_dir, recursive = TRUE) + } else { + stop("Run directory for ", crop, " in ", scenario, "\n", run_dir, "\nalready exists") + } + } + + # Create the run directory + dir.create(run_dir, recursive = TRUE) + + # Copy the psm file + psm_file <- file.path(psm_dir, paste0(psm, ".psm")) + file.copy(psm_file, run_dir) + + # Copy Haude factors + file.copy(file.path(PELMO_base, "FOCUS", "HAUDE.DAT"), file.path(run_dir, "Haude.dat")) + + # Copy scenario file + sze_file_upper <- paste0(location_code, "_", + toupper(FOCUS_PELMO_crop_sze_names[crop]), ".sze") + sze_file_lower <- paste0(location_code, "_", + FOCUS_PELMO_crop_sze_names[crop], ".sze") + if (file.exists(file.path(PELMO_base, "FOCUS", sze_file_lower))) { + sze_file <- sze_file_lower + } else { + if (file.exists(file.path(PELMO_base, "FOCUS", sze_file_upper))) { + sze_file <- sze_file_upper + } else { + stop("Could not find szenario file for ", crop, " in ", scenario) + } + } + file.copy(file.path(PELMO_base, "FOCUS", sze_file), file.path(run_dir, sze_file_lower)) + + # Generate PELMO input file + input_file <- file(file.path(run_dir, "pelmo.inp"), encoding = "latin1", open = "w+") + on.exit(close(input_file)) + + add <- function(x) cat(paste0(x, "\r\n"), file = input_file, append = TRUE) + + # How many years do we calculate (26, 46 or 66)? + psm <- readLines(psm_file, encoding = "latin1") + number_of_apps_lines <- grep("number of application location", psm) + absolute_apps_line <- grep(location_code, + psm[number_of_apps_lines]) + period <- 1 # application every year + if (length(absolute_apps_line) == 1) { + apps_root <- number_of_apps_lines[absolute_apps_line] + } else { + apps_root <- number_of_apps_lines[1] + } + + number_of_apps <- as.integer(substr(psm[apps_root], 1, 3)) + last_app_line <- psm[apps_root + number_of_apps] + last_app_year <- as.integer(gsub("^.{2,3} .. (..) .*", "\\1", + last_app_line)) + if (last_app_year > 26) period <- 2 + if (last_app_year > 46) period <- 3 + + n_years <- switch(as.character(period), + "1" = 26, + "2" = 46, + "3" = 66) + + # First line with number of climate years + add(paste0(formatC(n_years, width = 3, flag = "0"), + " 01 01 31 12 Version ", substr(version, 1, 1))) + + # Second line with scenario file (why did we copy it, if this line refers to the FOCUS dir... + add(paste0("..\\..\\..\\", sze_file_lower)) + + # Third line with psm file + add(basename(psm_file)) + + # Lines with climate files + for (year in 1:n_years) { + add(paste0("..\\..\\..\\", location_code, "_", formatC(year, width = 2, flag = "0"), ".cli")) + } + + # Output control section + add("00000015 00.") + add(" PRSN TSER 000.0 1.0 00000001") + add(" TETD TSER 000.0 1.0 00000001") + add(" INFL TSER 100.0 1.0 00000001") + add(" RUNF TSER 000.0 1.0 00000001") + add(" THET TSER 000.0 1.0 00000001") + add(" THET TSER 030.0 1.0 00000001") + add(" TEMP TSER 000.0 1.0 00000001") + add(" TEMP TSER 030.0 1.0 00000001") + add(" TPAP TSER 000.0 1.0E05 00000001") + add(" TDKF TSER 000.0 1.0E05 00000001") + add(" TUPF TSER 000.0 1.0E05 00000001") + add(" TPST TSER 005.0 1.0E06 00000001") + add(" PFLX TSER 100.0 1.0E05 00000001") + add(" RFLX TSER 000.0 1.0E05 00000001") + add(" LEAC TSER 100.0 1.0E09 00000001") + + # Copy pelmo executable + file.copy(PELMO_exe, run_dir) + + # In addition to the files copied by the FOCUS PELMO GUI, we + # need the error file in the run directory, as we start + # the exe file from this directory + file.copy(file.path(PELMO_base, "lf90.eer"), run_dir) + } + + lapply(run_list, setup_run) + + if (execute) { + run_PELMO(runs, version = version, PELMO_base = PELMO_base) + } +} + +#' Run PELMO +#' +#' @inheritParams PELMO_runs +#' @importFrom parallel mclapply +#' @export +run_PELMO <- function(runs, psm_dir = ".", version = "5.5.3", PELMO_base = "auto", + cores = getOption("mc.cores", 2L)) +{ + + if (PELMO_base[1] == "auto") { + PELMO_base = file.path(system.file(package = "PELMO.installeR"), + paste0("FOCUSPELMO.", gsub("\\.", "", version))) + } + + pelmo_exe = list.files(PELMO_base, "^pelmo.*.exe") + + # Create list of runs to traverse using mclapply + run_list <- create_run_list(runs, check_psm_files = FALSE) + + # In order to run in parallel, we need to make a directory tree starting + # from the base of the PELMO installation, as pelmo401.exe seems to look + # for ..\..\..\summary.PLM and does not start if this is in use by another + # instance + run_exe <- function(x) { + psm <- x$psm + crop <- x$crop + scenario <- x$scenario + run_dir <- file.path(PELMO_base, "FOCUS", PELMO_path(psm, crop, scenario)) + exe_dir <- file.path(PELMO_base, paste(sample(c(0:9, letters, LETTERS), + size = 8, replace = TRUE), + collapse = "")) + dir.create(exe_dir) + + # Fresh PELMO base directory for every run with random name + run_dir_exe <- file.path(exe_dir, "FOCUS", PELMO_path(psm, crop, scenario)) + dir.create(run_dir_exe, recursive = TRUE) + + # Copy the contents of the run directory + run_files <- list.files(run_dir, full.names = TRUE) + file.copy(run_files, run_dir_exe) + + # Copy FOCUS files + location_code <- FOCUS_PELMO_location_codes[x$scenario] + location_files <- list.files(file.path(PELMO_base, "FOCUS"), paste0("^", location_code), + full.names = TRUE) + focus_dir_exe <- file.path(exe_dir, "FOCUS") + file.copy(location_files, focus_dir_exe) + file.copy(file.path(PELMO_base, "FOCUS", "FOCUSCHECK.DAT"), focus_dir_exe) + + # We need to go the directory to simplify calling pelmo with wine + setwd(run_dir_exe) + psm_file <- file.path(psm_dir, paste0(psm, ".psm")) + system(paste("wine", pelmo_exe, psm_file), ignore.stdout = TRUE) + + # Copy the results to the original run directory + plm_files <- list.files(run_dir_exe, ".plm$", full.names = TRUE) + PLM_files <- list.files(run_dir_exe, ".PLM$", full.names = TRUE) + file.copy(c(plm_files, PLM_files), run_dir) + + # Clean up + unlink(exe_dir, recursive = TRUE) + } + + mclapply(run_list, run_exe, mc.cores = cores) +} + +#' Create a path of run directories as the PELMO GUI does +#' +#' @export +#' @importFrom utils data +#' @param psm The psm identifier +#' @param crop The PELMO crop acronym +#' @param scenario The scenario +PELMO_path <- function(psm, crop, scenario) { + if (crop %in% names(FOCUS_PELMO_crops)) { + crop <- FOCUS_PELMO_crops[crop] + } + if (!crop %in% FOCUS_PELMO_crops) stop(crop, " is not in FOCUS_PELMO_crops.") + psm_dir <- paste0(psm, ".run") + crop_dir <- paste0(gsub(" ", "_-_", crop), ".run") + + # Deal with 'irrigation'. It only affects the naming of the scenario directory, + # but it does not appear to affect the PELMO run. This can be seen when + # comparing runs set up for Beans (field) and Beans (vegetable) for the Porto + # scenario + irrigation_string <- "" + + # 'Irrigation' is only possible in the GUI for five scenarios + if (scenario %in% c("Cha", "Pia", "Por", "Sev", "Thi")) { + crop_acronyms <- names(FOCUS_PELMO_crops) + names(crop_acronyms) <- FOCUS_PELMO_crops + crop_acronym <- crop_acronyms[[crop]] + # Some crops are not 'irrigated' according to the GUI + if (crop_acronym %in% c("win", "fbe", "woi", "ape", "spr")) { + irrigation_string <- "--_-_no_-_irrigation" + } else { + irrigation_string <- "--_-_irrigated" + } + } + + scenario_dir <- paste0( + FOCUS_GW_scenarios_2012$names[scenario], "_-_(", FOCUS_PELMO_location_codes[scenario], ")", + irrigation_string, ".run") + + return(file.path(psm_dir, crop_dir, scenario_dir)) +} + +#' Create a list of runs that we can traverse +#' +#' @inheritParams PELMO_runs +#' @param check_psm_files Should we check if the psm file exists +create_run_list <- function(runs, psm_dir = ".", check_psm_files = FALSE) { + i <- 0 + run_list <- list() + for (run in runs) { + psm <- run$psm + if (check_psm_files) { + psm_file <- file.path(psm_dir, paste0(psm, ".psm")) + if (file.access(psm_file) == -1) { + stop(psm_file, " is not readable") + } + } + crops <- setdiff(names(run), "psm") + for (crop in crops) { + crop_acronyms <- names(FOCUS_PELMO_crops) + names(crop_acronyms) <- FOCUS_PELMO_crops + if (!crop %in% crop_acronyms) { + if (crop %in% FOCUS_PELMO_crops) { + crop <- crop_acronyms[crop] + } else { + stop("Invalid crop specification ", crop) + } + } + for (scenario in run[[crop]]) { + i <- i + 1 + run_list[[i]] <- list(psm = psm, crop = crop, scenario = scenario) + } + } + } + return(run_list) +} |