From 143d21a9b69aecfd626a14be92807a08b70f1de8 Mon Sep 17 00:00:00 2001
From: Delaigue Olivier <olivier.delaigue@irstea.priv>
Date: Tue, 16 Apr 2019 17:24:43 +0200
Subject: [PATCH] v1.2.14.0 NEW: power transformation allowed in
 CreateInputsCrit

---
 DESCRIPTION             |  4 ++--
 NEWS.rmd                | 17 ++++++++++++++---
 R/CreateInputsCrit.R    | 42 ++++++++++++++++++++++++++---------------
 man/CreateInputsCrit.Rd |  2 +-
 4 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index 688b7a90..4f98a4d7 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,8 +1,8 @@
 Package: airGR
 Type: Package
 Title: Suite of GR Hydrological Models for Precipitation-Runoff Modelling
-Version: 1.2.13.17
-Date: 2019-04-04
+Version: 1.2.14.0
+Date: 2019-04-16
 Authors@R: c(
   person("Laurent", "Coron", role = c("aut", "trl"), comment = c(ORCID = "0000-0002-1503-6204")),
   person("Olivier", "Delaigue", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-7668-8468"), email = "airGR@irstea.fr"),
diff --git a/NEWS.rmd b/NEWS.rmd
index 7c6eab96..30cdf6b4 100644
--- a/NEWS.rmd
+++ b/NEWS.rmd
@@ -14,7 +14,19 @@ output:
 
 
 
-### 1.2.13.17 Release Notes (2019-04-04)
+### 1.2.14.0 Release Notes (2019-04-16)
+
+
+#### New features
+
+- <code>CreateInputsCrit()</code> now allows power transformation (as numeric or character values) in the <code>transfo</code> argument.
+
+
+#### Minor user-visible changes
+
+- <code>ErrorCrit_&#42;()</code> functions now call <code>.ErrorCrit()</code> in order to check.
+
+____________________________________________________________________________________
 
 
 ### 1.2.13.16 Release Notes (2019-04-03)
@@ -43,7 +55,7 @@ output:
 
 - <code>CreateInputsCrit()</code> now presents a <code>warnings</code> argument to replace the verbose action (the <code>verbose</code> argument is kept to print messages).
 
-- In <code>CreateInputsCrit()</code>, it is now possible to set the following arguments as atomic (as before) or as list: <code>FUN_CRIT</code>, <code>VarObs</code>, <code>Obs</code>, <code>BoolCrit</code>, <code>transfo</code>, <code>Weights</code>. If the list format is chosen, all the lists must have the same length. XXXXX mélange new args et usage XXXX
+- In <code>CreateInputsCrit()</code>, it is now possible to set the following arguments as atomic (as before) or as list: <code>FUN_CRIT</code>, <code>VarObs</code>, <code>Obs</code>, <code>BoolCrit</code>, <code>transfo</code>, <code>Weights</code>. If the list format is chosen, all the lists must have the same length.
 
 - <code>CreateRunOptions()</code>, <code>CreateIniStates()</code> and <code>CreateCalibOptions()</code> now present a <code>IsHyst</code> argument to give the possibility to use the Linear Hysteresis with CemaNeige. The objects returned present an <code>hysteresis</code> class.
 
@@ -58,7 +70,6 @@ output:
 
 #### Major user-visible changes
 
-
 - <code>CreateInputsCrit()</code> now return a list of <code>InputsCrit</code> (each element is of the <code>Single</code> class) in the cases of multiple or a composite criteria.
 
 - <code>ErrorCrit_&#42;()</code> functions now return an error message if the <code>InputsCrit</code> object is of class <code>Multi</code> or <code>Compo</code>.
diff --git a/R/CreateInputsCrit.R b/R/CreateInputsCrit.R
index 02880748..e7df0f07 100644
--- a/R/CreateInputsCrit.R
+++ b/R/CreateInputsCrit.R
@@ -57,15 +57,15 @@ CreateInputsCrit <- function(FUN_CRIT,
     Obs <- list(Obs)
   } else {
     idLayer <- lapply(Obs, function(i) {
-        if (is.list(i)) {
-          length(i)
-        } else {
-          1L
-        }
-      })
+      if (is.list(i)) {
+        length(i)
+      } else {
+        1L
+      }
+    })
     Obs <- lapply(Obs, function(x) rowMeans(as.data.frame(x)))
   }
-
+  
   
   ## create list of arguments
   listArgs <- list(FUN_CRIT   = FUN_CRIT,
@@ -73,7 +73,7 @@ CreateInputsCrit <- function(FUN_CRIT,
                    VarObs     = VarObs,
                    BoolCrit   = BoolCrit,
                    idLayer    = idLayer,
-                   transfo    = transfo,
+                   transfo    = as.character(transfo),
                    Weights    = Weights,
                    epsilon    = epsilon)
   
@@ -119,7 +119,7 @@ CreateInputsCrit <- function(FUN_CRIT,
   if ("SWE" %in% VarObs & inherits(RunOptions, "CemaNeige") & !"SnowPack" %in% RunOptions$Outputs_Sim) {
     stop("'SnowPack' is missing in 'Outputs_Sim' of 'RunOptions', which is necessary to output SWE with CemaNeige")
   }
-
+  
   
   ## check 'transfo'
   if (missing(transfo)) {
@@ -146,7 +146,7 @@ CreateInputsCrit <- function(FUN_CRIT,
   if (length(listArgs$Weights) > 1 & sum(unlist(listArgs$Weights)) == 0 & !any(sapply(listArgs$Weights, is.null))) {
     stop("sum of 'Weights' cannot be equal to zero")
   }
-
+  
   
   ## ---------- reformat
   
@@ -157,8 +157,8 @@ CreateInputsCrit <- function(FUN_CRIT,
   inVarObs  <- c("Q", "SCA", "SWE")
   msgVarObs <- "'VarObs' must be a (list of) character vector(s) and one of %s"
   msgVarObs <- sprintf(msgVarObs, paste(sapply(inVarObs, shQuote), collapse = ", "))
-  inTransfo  <- c("", "sqrt", "log", "inv", "sort")
-  msgTransfo <- "'transfo' must be a (list of) character vector(s) and one of %s"
+  inTransfo  <- c("", "sqrt", "log", "inv", "sort") # pow is not checked by inTransfo, but appears in the warning message and checkef after (see ## check 'transfo')
+  msgTransfo <- "'transfo' must be a (list of) character vector(s) and one of %s, or numeric value for power transformation"
   msgTransfo <- sprintf(msgTransfo, paste(sapply(inTransfo, shQuote), collapse = ", "))
   
   
@@ -216,6 +216,9 @@ CreateInputsCrit <- function(FUN_CRIT,
       } else {
         vecQSS <- unlist(iListArgs2$Obs[idQSS])
       }
+      if (all(is.na(vecQSS))) {
+        stop("'Obs' contains only missing values", call. = FALSE)
+      }
       if (min(vecQSS, na.rm = TRUE) < 0) {
         stop(sprintf("'Obs' outside [0,Inf[ for \"%s\"", iListArgs2$VarObs), call. = FALSE)
       }
@@ -223,9 +226,18 @@ CreateInputsCrit <- function(FUN_CRIT,
     
     
     ## check 'transfo'
-    if (is.null(iListArgs2$transfo) | !is.vector(iListArgs2$transfo) | length(iListArgs2$transfo) != 1 | !is.character(iListArgs2$transfo) | !all(iListArgs2$transfo %in% inTransfo)) {
+    if (is.null(iListArgs2$transfo) | !is.vector(iListArgs2$transfo) | length(iListArgs2$transfo) != 1 | !is.character(iListArgs2$transfo)) {
       stop(msgTransfo, call. = FALSE)
     }
+    isNotInTransfo <- !(iListArgs2$transfo %in% inTransfo)
+    if (any(isNotInTransfo)) {
+      powTransfo <- iListArgs2$transfo[isNotInTransfo]
+      numExpTransfo <- suppressWarnings(as.numeric(powTransfo))
+      if (any(is.na(numExpTransfo))) {
+        stop(msgTransfo, call. = FALSE)
+      }
+      iListArgs2$transfo <- paste0("^", iListArgs2$transfo)
+    }
     
     ## check 'Weights'
     if (!is.null(iListArgs2$Weights)) {
@@ -253,7 +265,7 @@ CreateInputsCrit <- function(FUN_CRIT,
         warning(sprintf(warn_log_kge, "KGE'"), call. = FALSE)
       }
     }
-
+    
     ## Create InputsCrit
     iInputsCrit <- list(FUN_CRIT   = iListArgs2$FUN_CRIT,
                         Obs        = iListArgs2$Obs,
@@ -310,7 +322,7 @@ CreateInputsCrit <- function(FUN_CRIT,
       }
     }
   }
-
+  
   
   ## if only one criterion --> not a list of InputsCrit but directly an InputsCrit
   if (length(InputsCrit) < 2) {
diff --git a/man/CreateInputsCrit.Rd b/man/CreateInputsCrit.Rd
index e35d4e29..07ee3b2b 100644
--- a/man/CreateInputsCrit.Rd
+++ b/man/CreateInputsCrit.Rd
@@ -32,7 +32,7 @@ CreateInputsCrit(FUN_CRIT, InputsModel, RunOptions,
 
 \item{BoolCrit}{(optional) [boolean (atomic or list)] boolean (the same length as \code{Obs}) giving the time steps to consider in the computation (all time steps are considered by default)}
 
-\item{transfo}{(optional) [character (atomic or list)] name of the transformation (e.g. \code{""}, \code{"sqrt"}, \code{"log"}, \code{"inv"}, \code{"sort"})}
+\item{transfo}{(optional) [character (atomic or list)] name of the transformation (e.g. \code{""}, \code{"sqrt"}, \code{"log"}, \code{"inv"}, \code{"sort"} or numeric value for power transformation (see details))}
 
 \item{Weights}{(optional) [numeric (atomic or list)] vector of weights necessary to calculate a composite criterion (the same length as \code{FUN_CRIT}) giving the weights to use for elements of \code{FUN_CRIT} [-]. See details}
 
-- 
GitLab