diff --git a/OperationalCS.R b/OperationalCS.R index 2f034dbc6a4cbf4a504304d3f6abf5df6e14b796..bdb960c8aca7240188c64b2f742948da91fc1247 100644 --- a/OperationalCS.R +++ b/OperationalCS.R @@ -8,6 +8,7 @@ print(args) library(yaml) # To test: +# args <- NULL; args[1] <- "recipes/conf_user.yml"; args[2] <- "recipes/tests/seasonal_testWorkflow1.yml" # args <- NULL; args[1] <- "recipes/conf_user.yml"; args[2] <- "recipes/seasonal_oper.yml" # args <- NULL; args[1] <- "recipes/conf_user.yml"; args[2] <- "recipes/seasonal_complex.yml" @@ -21,11 +22,13 @@ source("tools/libs.R") logger <- prepare_outputs(recipe = recipe, file = args[2], conf = conf) log_file <- logger$logname logger <- logger$logger + # Checks: check_conf(conf, file = args[1], logger) verifications <- check_recipe(recipe, file = args[2], conf, logger) # Go to verification code: -capture.output(source("modules/verifications.R"), file = log_file, type ='message', +capture.output(source("modules/verifications.R"), + file = log_file, type ='message', append = TRUE) diff --git a/modules/Calibration/Calibration.R b/modules/Calibration/Calibration.R new file mode 100644 index 0000000000000000000000000000000000000000..b86ea9593af21822b9eadd7967cb5df35c03b7ad --- /dev/null +++ b/modules/Calibration/Calibration.R @@ -0,0 +1,42 @@ +# Code to apply any correction method: +# simple bias adjustment +# variance inflation +# quantile mapping + +## Which parameter are required? +if (!("obs" %in% ls()) || is.null(obs)) { + error(logger, + "There is no object 'obs' in the global environment or it is NULL") + stop("EXECUTION FAILED") +} +if (stream == "fcst" && (!("fcst" %in% ls()) || is.null(fcst))) { + error(logger, + "There is no object 'fcst' in the global environment or it is NULL") + stop("EXECUTION FAILED") +} +if (!("hcst" %in% ls()) || is.null(hcst)) { + error(logger, + "There is no object 'hcst' in the global environment or it is NULL") + stop("EXECUTION FAILED") +} +if (!("method" %in% ls()) || is.null(method)) { + warn(logger, + "Calibration method not found and it is set as 'SBC'.") + method <- 'SBC' +} +if (method %in% c('SBC', 'SimpleBiasCorrection')) { + cal_fun <- "CSTools::Calibration" + cal_method <- "bias" +} else if (method %in% c("Inflation", "VarianceInflation")) { + cal_fun <- "CSTools::Calibration" + cal_method <- "evmos" +} else if (method %in% c("QM", "QuantileMapping")) { + cal_fun <- "CSTools::QuantileMapping" +} else { + error(logger, "Unknown calibration method definde in the recipe.") + stop("EXECUTION FAILED") +} +info(logger, paste("#-------------------------- ", "\n", + "running Calibration module", "\n", + "it can call", cal_fun )) + diff --git a/modules/Skill/Skill.R b/modules/Skill/Skill.R new file mode 100644 index 0000000000000000000000000000000000000000..e7cad0cb45a182571a383bbd00c9985c7886ae4f --- /dev/null +++ b/modules/Skill/Skill.R @@ -0,0 +1,43 @@ +# This module should calculate verification metrics at any time of the workflow +# It should implement different verification metrics: +# - FRPSS and RPSS +# - FCRPSS abd CRPSS +# - enscorr +# - bias +# - reliability diagram +# - ask Carlos which decadal metrics he is currently using + +## Which parameter are required? +if (!("obs" %in% ls()) || is.null(obs)) { + error(logger, + "There is no object 'obs' in the global environment or it is NULL") +} +if (stream == "fcst" && (!("fcst" %in% ls()) || is.null(fcst))) { + error(logger, + "There is no object 'fcst' in the global environment or it is NULL") +} +if (!("hcst" %in% ls()) || is.null(hcst)) { + error(logger, + "There is no object 'hcst' in the global environment or it is NULL") +} +if (!("metric" %in% ls()) || is.null(metric)) { + warn(logger, + "Verification metric not found and it is set as 'EnsCorr'.") + metric <- 'EnsCorr' +} +if (metric %in% c('FRPSS', 'RPSS')) { + metric_fun <- "veriApply" + metric_method <- "FairRpss" +} else if (metric %in% c("FCRPSS", "CRPSS")) { + metric_fun <- "veriApply" +} else if (metric %in% c("EnsCorr", "EnsCor")) { + metric_fun <- "veriApply" + metric_method <- "EnsCorr" +#... +} else { + error(logger, "Unknown verification metric defined in the recipe.") + metric_fun <- 'NotFound' +} +info(logger, paste("#-------------------------- ", "\n", + " running Skill module ", "\n", + " it can call ", metric_fun )) diff --git a/modules/verifications.R b/modules/verifications.R index 8078762c57963c0b248b31d8ae1d2367354a4184..2451b7d7f7dc57f636cacd0933d7afe6f03aacd1 100644 --- a/modules/verifications.R +++ b/modules/verifications.R @@ -1,5 +1,4 @@ for (indep in verifications$independent) { -print(indep) if (length(indep) == 1) { info(logger, paste(" #*****************************************#", @@ -41,8 +40,71 @@ print(indep) for (sdate in verifications$fcst.sdate) { fcst.sdate <- sdate source("modules/data_load/seas5.load.R") + # Translate $Workflow to call modules: + ## 1) Clean step of the workflow set as FALSE or NULL or None: + modules <- names(recipe$Analysis$Workflow) + for (mod in modules) { + if ((is.logical(recipe$Analysis$Workflow[[mod]][[1]]) && + recipe$Analysis$Workflow[[mod]][[1]] == FALSE) || + recipe$Analysis$Workflow[[mod]][[1]] == 'None' || + is.null(recipe$Analysis$Workflow[[mod]][[1]])) { + info(logger, + paste("The module", mod, "won't be executed.")) + recipe$Analysis$Workflow <- recipe$Analysis$Workflow[ + -which(names(recipe$Analysis$Workflow) == mod)] + } + } + modules <- names(recipe$Analysis$Workflow) + ## 2) Create a common format for all modules + tmp_modules <- list() + for (mod in modules) { + if (length(recipe$Analysis$Workflow[[mod]]) > 1) { + names(recipe$Analysis$Workflow[[mod]]) <- + rep(mod, length(recipe$Analysis$Workflow[[mod]])) + tmp_modules <- append(tmp_modules, + recipe$Analysis$Workflow[[mod]]) + } else { + tmp_modules <- append(tmp_modules, + recipe$Analysis$Workflow[mod]) + } + } + modules <- tmp_modules + ## 3) Call each module and pass arguments: + for (mod in 1:length(modules)) { + # In case multiple calls to a module e.g.: Skill_1 --> Skill + if (any(strsplit(names(modules)[mod], "")[[1]] == "_")) { + module_name <- substr(names(modules)[mod], start = 1, + stop = which(strsplit(names(modules)[mod], "")[[1]] == "_") - 1) + } else { + module_name <- names(modules)[mod] + } + info(logger, paste("Start running module", module_name)) + module_code <- file.path(conf$code_dir, "modules", + module_name, + paste0(module_name, ".R")) + # Define variables setup in the recipe + for (param in names(modules[[mod]])) { + if (length(modules[[mod]][[param]])) { + tmp <- paste(modules[[mod]][[param]], + collapse = ",") + } else { + tmp <- modules[[mod]][[param]] + } + info(logger, paste("Variable *", param, "* set as", tmp)) + assign(as.character(param), + modules[[mod]][[param]]) + } + source(module_code) + # TO DO: + # Check the arguments of each module can be an option here: + #... + info(logger, paste(module_name, "module run finished.")) + } + info(logger, paste(sdate, "start date finished.")) } + info(logger, paste(ref, "reference dataset finished.")) } + info(logger, paste(sys, "systemn finished.")) } } } diff --git a/recipes/tests/execute_tests.R b/recipes/tests/execute_tests.R new file mode 100644 index 0000000000000000000000000000000000000000..44292f1600a2e317c5f3d18a35db9e73d3b44bed --- /dev/null +++ b/recipes/tests/execute_tests.R @@ -0,0 +1,45 @@ +library(yaml) + +args <- NULL; +args[1] <- "recipes/conf_user.yml"; + +# Function to run tests: +# source_lines("/esarchive/scratch/nperez/git/startR/inst/doc/usecase/ex2_1_timedim.R", +# start = 4, end = 14) +source_lines <- function(file, start, end, ...) { + file.lines <- scan(file, what = character(), skip = start - 1, + nlines = end - start + 1, sep = '\n') + file.lines.collapsed <- paste(file.lines, collapse = '\n') + source(textConnection(file.lines.collapsed), ...) +} + +# ------------------------------------------ +# Section to check recipes that should work: +args[2] <- "recipes/tests/seasonal_testWorkflow1.yml" +source_lines("OperationalCS.R", start = 14, end = 50) +# Calibration method None --> raw data verification +args[2] <- "recipes/tests/seasonal_testWorkflow4.yml" +source_lines("OperationalCS.R", start = 14, end = 50) +# Calibration: None --> raw data verification +args[2] <- "recipes/tests/seasonal_testWorkflow5.yml" +source_lines("OperationalCS.R", start = 14, end = 50) +# Case Skill_1 and Skill_2 when multiple times needed +args[2] <- "recipes/tests/seasonal_testWorkflow7.yml" +source_lines("OperationalCS.R", start = 14, end = 50) +# Indicator +args[2] <- "recipes/tests/seasonal_testWorkflow8.yml" +source_lines("OperationalCS.R", start = 14, end = 50) + +# ------------------------------------------ +# Section to check recipes that should fail: +## This should fail because there is no Horizon: +args[2] <- "recipes/tests/seasonal_testWorkflow2.yml" +source_lines("OperationalCS.R", start = 14, end = 50) + +## This should fail because there are 2 Calibration options: +args[2] <- "recipes/tests/seasonal_testWorkflow3.yml" +source_lines("OperationalCS.R", start = 14, end = 50) + +## This fails because it is not allow repeating the name Skill +args[2] <- "recipes/tests/seasonal_testWorkflow6.yml" +source_lines("OperationalCS.R", start = 14, end = 50) diff --git a/recipes/tests/seasonal_testWorkflow1.yml b/recipes/tests/seasonal_testWorkflow1.yml new file mode 100644 index 0000000000000000000000000000000000000000..c3b876132ced9a482d78a14dd30f5f4e5b147abe --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow1.yml @@ -0,0 +1,51 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Calibration: + method: SBC + Skill: + - {metric: fRPSS, probs: [1/3, 2/3]} + - {metric: BSS10} + - {metric: BSS90} + - {metric: EnsCorr} + - {metric: Bias} + Indicators: + index: FALSE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow2.yml b/recipes/tests/seasonal_testWorkflow2.yml new file mode 100644 index 0000000000000000000000000000000000000000..e31e4e5ac3d84f0fa13974acdbad3d02fd748efc --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow2.yml @@ -0,0 +1,50 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Calibration: + method: SBC + Skill: + - {metric: fRPSS, probs: [1/3, 2/3]} + - {metric: BSS10} + - {metric: BSS90} + - {metric: EnsCorr} + - {metric: Bias} + Indicators: + index: FALSE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow3.yml b/recipes/tests/seasonal_testWorkflow3.yml new file mode 100644 index 0000000000000000000000000000000000000000..26754f23cab73cbc4ec27a06cb2fae5b3c8f6c0f --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow3.yml @@ -0,0 +1,50 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Calibration: + - {method: SBC} + - {method: VarianceInflation} + Skill: + - {metric: fRPSS, probs: [1/3, 2/3]} + - {metric: BSS10} + - {metric: BSS90} + - {metric: EnsCorr} + - {metric: Bias} + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow4.yml b/recipes/tests/seasonal_testWorkflow4.yml new file mode 100644 index 0000000000000000000000000000000000000000..2b7992eec82d89aa509f6020bf79993e8e28a456 --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow4.yml @@ -0,0 +1,51 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Calibration: + method: None + Skill: + - {metric: fRPSS, probs: [1/3, 2/3]} + - {metric: BSS10} + - {metric: BSS90} + - {metric: EnsCorr} + - {metric: Bias} + Indicators: + index: FALSE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow5.yml b/recipes/tests/seasonal_testWorkflow5.yml new file mode 100644 index 0000000000000000000000000000000000000000..04700ed9ac133998360e59a73f78aa01d9a4efed --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow5.yml @@ -0,0 +1,49 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Calibration: FALSE + Skill: + - {metric: fRPSS, probs: [1/3, 2/3]} + - {metric: BSS10} + - {metric: BSS90} + - {metric: EnsCorr} + - {metric: Bias} + Indicators: FALSE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow6.yml b/recipes/tests/seasonal_testWorkflow6.yml new file mode 100644 index 0000000000000000000000000000000000000000..45033b6f1ea992eae1123597249749f1bd72aec5 --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow6.yml @@ -0,0 +1,51 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Skill: + - {metric: EnsCorr} + - {metric: Bias} + Calibration: + method: SBC + Skill: + - {metric: EnsCorr} + - {metric: Bias} + Indicators: + index: FALSE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow7.yml b/recipes/tests/seasonal_testWorkflow7.yml new file mode 100644 index 0000000000000000000000000000000000000000..093f697cf5a1b503670856cbb5b020d2d79a1350 --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow7.yml @@ -0,0 +1,51 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + ECVs: + - {name: tas, freq: monthly_mean} + Indicators: + - None + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Skill_1: + - {metric: EnsCorr} + - {metric: Bias} + Calibration: + method: SBC + Skill_2: + - {metric: EnsCorr} + - {metric: Bias} + Indicators: + index: FALSE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/recipes/tests/seasonal_testWorkflow8.yml b/recipes/tests/seasonal_testWorkflow8.yml new file mode 100644 index 0000000000000000000000000000000000000000..b4e57216310637fdafebc7effd92fdf29b0e0549 --- /dev/null +++ b/recipes/tests/seasonal_testWorkflow8.yml @@ -0,0 +1,49 @@ +Description: + Author: N.Pérez-Zanón + Info: This is a test to transform s2s4e data-analysis for SEAS5 + +Analysis: + Horizon: Seasonal + Variables: + Indicators: + - {name: gdd} + Datasets: + System: + - name: system5c3s + Multimodel: False + Reference: + - {name: era5} + Time: + sdate: + fcst_year: 2021 + fcst_month: 07 + fcst_day: 01 + hcst_start: 2000 + hcst_end: 2002 + leadtimemin: 2 + leadtimemax: 4 + Region: + Global: TRUE + Aggregation: False + Regional: + - {latmin: -90, latmax: 90, lonmin: 0, lonmax: 360} + - {latmin: -10, latmax: 10, lonmin: 0, lonmax: 20} + Regrid: + method: bilinear + type: system + Workflow: + Calibration: + method: SBC + Skill: + - {metric: fRPSS, probs: [1/3, 2/3]} + - {metric: BSS10} + - {metric: BSS90} + - {metric: EnsCorr} + - {metric: Bias} + Indicators: + index: TRUE + Output_format: S2S4E + +Run: + Loglevel: INFO + Terminal: TRUE diff --git a/tools/check_recipe.R b/tools/check_recipe.R index 3fea5594c65f3d1cb691c1cfc45bdf745d00319b..2b7479d65cc9d993ab8d04587ff9a8d4e557d08e 100644 --- a/tools/check_recipe.R +++ b/tools/check_recipe.R @@ -11,23 +11,31 @@ check_recipe <- function(recipe, file, conf, logger) { params <- c('Horizon', 'Time', 'Variables', 'Region', 'Regrid', 'Workflow', 'Datasets') if (!all(params %in% names(recipe$Analysis))) { + params <- paste(params, collapse = ' ') error(logger, paste("The element 'Analysis' in the recipe should contain these", - "elements:", paste(params, collapse = " "))) + "elements:", params)) + stop("EXECUTION FAILED") } horizons <- c('Subseasonal', 'Seasonal', 'Decadal') if (!any(horizons %in% recipe$Analysis$Horizon)) { + horizons <- paste(horizons, collapse = " ") error(logger, - "The element 'Horizon' in the recipe should be one of the followings:", - paste(horizons, collapse = " ")) + paste("The element 'Horizon' in the recipe", + "should be one of the followings:", + horizons)) + stop("EXECUTION FAILED") } # Check temporal settings and # count the number of verifications - time_settings <- c('sdate', 'leadtimemin', 'leadtimemax', 'hcst_start', 'hcst_end') + time_settings <- c('sdate', 'leadtimemin', 'leadtimemax', + 'hcst_start', 'hcst_end') if (!all(time_settings %in% names(recipe$Analysis$Time))) { + time_settings <- paste(time_settings, collapse = " ") error(logger, paste("The element 'Time' in the recipe should contain these elements:", - paste(time_settings, collapse = " "))) + time_settings)) + stop("EXECUTION FAILED") } if (is.null(recipe$Analysis$Time$sdate$fcst_year) || recipe$Analysis$Time$sdate$fcst_year == 'None') { @@ -63,33 +71,56 @@ check_recipe <- function(recipe, file, conf, logger) { if (length(recipe$Analysis$Regrid) != 2) { error(logger, "The 'Regrid' element should specified the 'method' and 'type'.") + stop("EXECUTION FAILED") } # more checks # ... # calculate number of workflows to create for each variable and if (length(recipe$Analysis$Horizon) > 1) { - error(logger, "Only 1 Horizon can be specified in the recipe") + error(logger, "Only 1 Horizon can be specified in the recipe") + stop("EXECUTION FAILED") } nvar <- length(recipe$Analysis$Variables) if (nvar > 2) { error(logger, "Only two type of Variables can be listed: ECVs and Indicators.") + stop("EXECUTION FAILED") } # remove NULL or None Indicators or ECVs from the recipe: - if (!is.list(recipe$Analysis$Variables$Indicators)) { + if (!is.null(recipe$Analysis$Variables$Indicators) && + !is.list(recipe$Analysis$Variables$Indicators)) { recipe$Analysis$Variables <- recipe$Analysis$Variables[ -which(names(recipe$Analysis$Variables) == 'Indicators')] } - if (!is.list(recipe$Analysis$Variables$ECVs)) { + if (!is.null(recipe$Analysis$Variables$ECVs) && + !is.list(recipe$Analysis$Variables$ECVs)) { recipe$Analysis$Variables <- recipe$Analysis$Variables[ -which(names(recipe$Analysis$Variables) == 'ECVs')] } + # Only one Calibration method allowed: + if ((is.logical(recipe$Analysis$Workflow$Calibration[[1]]) && + recipe$Analysis$Workflow$Calibration[[1]] == FALSE) || + recipe$Analysis$Workflow$Calibration[[1]] == 'None' || + is.null(recipe$Analysis$Workflow$Calibration[[1]])) { + warn(logger, + "There is no Calibration method selected, raw data verification.") + recipe$Analysis$Workflow$Calibration[[1]] <- FALSE + } else { + # remove multiple calibration methods + if (is.null(names(recipe$Analysis$Workflow$Calibration))) { + error(logger, + "The 'Calibration' element should specified at least the 'method'.") + stop("EXECUTION FAILED") + } + } if (length(recipe$Analysis$Region) > 3) { error(logger, "The section 'Region' in the recipe should be checked.", "Global, Countries and Regional elements are expected.") + stop("EXECUTION FAILED") } if (!is.logical(recipe$Analysis$Region$Global)) { error(logger, "The element 'Global' in Region should be logical.") + stop("EXECUTION FAILED") } nregions <- 0 if (recipe$Analysis$Region$Global == TRUE) { @@ -103,9 +134,12 @@ check_recipe <- function(recipe, file, conf, logger) { limits <- c('latmin', 'latmax', 'lonmin', 'lonmax') for (i in 1:length(recipe$Analysis$Region$Regional)) { if (!all(limits %in% names(recipe$Analysis$Region$Regional[[i]]))) { + limits <- paste(limits, collapse = " ") error(logger, - "Each region defined in element 'Regional' should have 4 elements:", - paste(limits, collapse = " ")) + paste("Each region defined in element 'Regional'", + "should have 4 elements:", + limits)) + stop("EXECUTION FAILED") } # are numeric? class list mode list }