diff --git a/R/CreateCalibOptions.R b/R/CreateCalibOptions.R
index fc71940be53f63ee7ff9d7b93ccf398e1b434ce3..d944d9dc7954eec2567409b17a2e4cbebf6ec3b2 100644
--- a/R/CreateCalibOptions.R
+++ b/R/CreateCalibOptions.R
@@ -23,17 +23,21 @@ CreateCalibOptions <- function(x, ...) {
 #' @export
 CreateCalibOptions.InputsModel <- function(x,
                                            ...) {
-  if (!exists("FUN_MOD") && !is.null(x$FUN_MOD)) {
-    airGR::CreateCalibOptions(
-      FUN_MOD = x$FUN_MOD,
-      IsSD = !is.null(x$Qupstream) & x$FUN_MOD != "RunModel_Lag",
-      ...
-    )
-  } else {
-    airGR::CreateCalibOptions(
-      ...
-    )
+  dots <- list(...)
+  # Add FUN_MOD in parameters if carried by InputsModel
+  if (!"FUN_MOD" %in% names(dots)) {
+    if(!is.null(x$FUN_MOD)) {
+      dots$FUN_MOD <- x$FUN_MOD
+    } else {
+      stop(" The parameter `FUN_MOD` must be defined")
+    }
   }
+  # Automatically define IsSD for intermediate basin GR models
+  dots$IsSD = !is.null(x$Qupstream) & dots$FUN_MOD != "RunModel_Lag"
+  # Add IsHyst in parameters if carried by InputsModel
+  if (!is.null(x$model$IsHyst)) dots$IsHyst <- x$model$IsHyst
+  # Call airGR function
+  do.call(airGR::CreateCalibOptions, dots)
 }
 
 #' @rdname CreateCalibOptions
diff --git a/R/CreateInputsModel.GRiwrm.R b/R/CreateInputsModel.GRiwrm.R
index 50edf1fbd53f26d05818c1278dba3c69eaa90001..115916133134eee00fa8783bdb8234d88c67e920 100644
--- a/R/CreateInputsModel.GRiwrm.R
+++ b/R/CreateInputsModel.GRiwrm.R
@@ -35,6 +35,8 @@
 #' @param NLayers (optional) named [vector] of [numeric] integer giving the number
 #'        of elevation layers requested [-], required to create CemaNeige module
 #'        inputs, default=5
+#' @param IsHyst [logical] boolean indicating if the hysteresis version of
+#'        CemaNeige is used. See details of [airGR::CreateRunOptions].
 #' @param ... used for compatibility with S3 methods
 #'
 #' @details Meteorological data are needed for the nodes of the network that
@@ -70,7 +72,8 @@ CreateInputsModel.GRiwrm <- function(x, DatesR,
                                      PrecipScale = TRUE,
                                      TempMean = NULL, TempMin = NULL,
                                      TempMax = NULL, ZInputs = NULL,
-                                     HypsoData = NULL, NLayers = 5, ...) {
+                                     HypsoData = NULL, NLayers = 5,
+                                     IsHyst = FALSE, ...) {
 
   # Check and format inputs
   varNames <- c("Precip", "PotEvap", "TempMean", "Qobs", "Qmin",
@@ -212,7 +215,8 @@ CreateInputsModel.GRiwrm <- function(x, DatesR,
                                  HypsoData = getInputBV(HypsoData, id),
                                  NLayers = getInputBV(NLayers, id, 5),
                                  Qobs = Qobs,
-                                 Qmin = getInputBV(Qmin, id)
+                                 Qmin = getInputBV(Qmin, id),
+                                 IsHyst = IsHyst
                                  )
   }
   attr(InputsModel, "TimeStep") <- getModelTimeStep(InputsModel)
@@ -247,7 +251,7 @@ CreateEmptyGRiwrmInputsModel <- function(griwrm) {
 #'
 #' @return \emph{InputsModel} object for one.
 #' @noRd
-CreateOneGRiwrmInputsModel <- function(id, griwrm, ..., Qobs, Qmin) {
+CreateOneGRiwrmInputsModel <- function(id, griwrm, ..., Qobs, Qmin, IsHyst) {
   np <- getNodeProperties(id, griwrm)
 
   if (np$Diversion) {
@@ -326,7 +330,7 @@ CreateOneGRiwrmInputsModel <- function(id, griwrm, ..., Qobs, Qmin) {
 
   # Add the model function
   InputsModel$FUN_MOD <- FUN_MOD
-  featModel <- .GetFeatModel(InputsModel)
+  featModel <- .GetFeatModel(InputsModel, IsHyst)
   InputsModel$isUngauged <- griwrm$model[griwrm$id == id] == "Ungauged"
   InputsModel$gaugedId <- griwrm$donor[griwrm$id == id]
   InputsModel$hasUngaugedNodes <- hasUngaugedNodes(id, griwrm)
@@ -334,8 +338,9 @@ CreateOneGRiwrmInputsModel <- function(id, griwrm, ..., Qobs, Qmin) {
     list(
       indexParamUngauged = ifelse(inherits(InputsModel, "SD"), 0, 1) +
         seq.int(featModel$NbParam),
-      hasX4 = grepl("RunModel_GR[456][HJ]", FUN_MOD),
-      iX4 = ifelse(inherits(InputsModel, "SD"), 5, 4)
+      hasX4 = grepl("RunModel_(CemaNeige|)GR[456][HJ]", FUN_MOD),
+      iX4 = ifelse(inherits(InputsModel, "SD"), 5, 4),
+      IsHyst = featModel$IsHyst
     )
   InputsModel$hasDiversion <- np$Diversion
   InputsModel$isReservoir <- np$Reservoir
@@ -446,7 +451,7 @@ hasUngaugedNodes <- function(id, griwrm) {
 #' function to extract model features partially copied from airGR:::.GetFeatModel
 #' @importFrom utils tail
 #' @noRd
-.GetFeatModel <- function(InputsModel) {
+.GetFeatModel <- function(InputsModel, IsHyst) {
   path <- system.file("modelsFeatures/FeatModelsGR.csv", package = "airGR")
   FeatMod <- read.table(path, header = TRUE, sep = ";", stringsAsFactors = FALSE)
   NameFunMod <- ifelse(test = FeatMod$Pkg %in% "airGR",
@@ -461,6 +466,13 @@ hasUngaugedNodes <- function(id, griwrm) {
   if (FeatMod$IsSD) {
     FeatMod$NbParam <- FeatMod$NbParam + 1
   }
+  FeatMod$IsHyst <- FALSE
+  if (grepl("CemaNeige", FeatMod$NameMod)) {
+    FeatMod$IsHyst <- IsHyst
+    if (IsHyst) {
+      FeatMod$NbParam <- FeatMod$NbParam + 2
+    }
+  }
   return(FeatMod)
 }
 
diff --git a/R/CreateRunOptions.R b/R/CreateRunOptions.R
index e6762391d008c9c850e558160ca951d6ca8f56c7..c74cc68539bd87d676e1d2428b9cc1ddd63c239a 100644
--- a/R/CreateRunOptions.R
+++ b/R/CreateRunOptions.R
@@ -43,6 +43,8 @@ CreateRunOptions.InputsModel <- function(x, ...) {
       stop(" The parameter `FUN_MOD` must be defined")
     }
   }
+  # Add IsHyst in parameters if carried by InputsModel
+  if (!is.null(x$model$IsHyst)) dots$IsHyst <- x$model$IsHyst
 
   # Temporary fix waiting for resolution of HYCAR-Hydro/airgr#167
   if (identical(match.fun(dots$FUN_MOD), RunModel_Lag)) {
diff --git a/man/CreateInputsModel.GRiwrm.Rd b/man/CreateInputsModel.GRiwrm.Rd
index f77b5cebec78cbbdab61ae6f8839cfb17ede6077..26b9a66bc318a276b31f98ce25216ad896e2e9db 100644
--- a/man/CreateInputsModel.GRiwrm.Rd
+++ b/man/CreateInputsModel.GRiwrm.Rd
@@ -18,6 +18,7 @@
   ZInputs = NULL,
   HypsoData = NULL,
   NLayers = 5,
+  IsHyst = FALSE,
   ...
 )
 }
@@ -70,6 +71,9 @@ if not defined a single elevation is used for CemaNeige}
 of elevation layers requested \link{-}, required to create CemaNeige module
 inputs, default=5}
 
+\item{IsHyst}{\link{logical} boolean indicating if the hysteresis version of
+CemaNeige is used. See details of \link[airGR:CreateRunOptions]{airGR::CreateRunOptions}.}
+
 \item{...}{used for compatibility with S3 methods}
 }
 \value{
diff --git a/tests/testthat/helper_1_RunModel.R b/tests/testthat/helper_1_RunModel.R
index 565d840b3609b927d2f389ba54df9d02106b9e62..3e9acbede60e83b4f6ad62b24b4d4f1a59ce50fb 100644
--- a/tests/testthat/helper_1_RunModel.R
+++ b/tests/testthat/helper_1_RunModel.R
@@ -15,7 +15,8 @@ setupRunModel <-
            runRunOptions = TRUE,
            runRunModel = TRUE,
            griwrm = NULL,
-           Qobs2 = NULL) {
+           Qobs2 = NULL,
+           IsHyst = FALSE) {
 
     data(Severn)
 
@@ -43,12 +44,20 @@ setupRunModel <-
     # Convert meteo data to SD (remove upstream areas)
     Precip <- ConvertMeteoSD(griwrm, PrecipTot)
     PotEvap <- ConvertMeteoSD(griwrm, PotEvapTot)
+    if (IsHyst) {
+      TempMean <- PotEvap+5 # Fake temperatures
+    } else {
+      TempMean <- NULL
+    }
 
     # set up inputs
     if (!runInputsModel)
       return(environment())
     InputsModel <-
-      suppressWarnings(CreateInputsModel(griwrm, DatesR, Precip, PotEvap, Qobs = Qobs2))
+      suppressWarnings(CreateInputsModel(griwrm, DatesR, Precip, PotEvap,
+                                         TempMean = TempMean,
+                                         Qobs = Qobs2,
+                                         IsHyst = IsHyst))
 
     # RunOptions
     if (!runRunOptions)
diff --git a/tests/testthat/helper_Calibration.R b/tests/testthat/helper_Calibration.R
index c2928118c67bc5c677964329fa5947a110a2e6bb..08dc63672e9cff31494c3ebff5f344520423ed00 100644
--- a/tests/testthat/helper_Calibration.R
+++ b/tests/testthat/helper_Calibration.R
@@ -1,14 +1,19 @@
 runCalibration <- function(nodes = NULL,
                            Qobs2 = NULL,
                            InputsCrit = NULL,
+                           CalibOptions = NULL,
                            FUN_CRIT = ErrorCrit_KGE2,
-                           runRunModel = FALSE) {
+                           runRunModel = FALSE,
+                           IsHyst = FALSE) {
   if (is.null(nodes)) {
     griwrm <- NULL
   } else {
     griwrm <- CreateGRiwrm(nodes)
   }
-  e <- setupRunModel(griwrm = griwrm, runRunModel = runRunModel, Qobs2 = Qobs2)
+  e <- setupRunModel(griwrm = griwrm,
+                     runRunModel = runRunModel,
+                     Qobs2 = Qobs2,
+                     IsHyst = IsHyst)
   for(x in ls(e)) assign(x, get(x, e))
   rm(e)
   np <- getAllNodesProperties(griwrm)
@@ -22,7 +27,8 @@ runCalibration <- function(nodes = NULL,
     )
   }
 
-  CalibOptions <- CreateCalibOptions(InputsModel)
+  if (is.null(CalibOptions)) CalibOptions <- CreateCalibOptions(InputsModel)
+
   OutputsCalib <- Calibration(InputsModel, RunOptions, InputsCrit, CalibOptions)
   Param <- sapply(OutputsCalib, "[[", "ParamFinalR")
   return(environment())
diff --git a/tests/testthat/test-RunModel_Ungauged.R b/tests/testthat/test-RunModel_Ungauged.R
index 1a03a4fd329df7e13dfe3432a35fe881dad652f0..5b6dd7bc0ea885da64c547ceb9fad707a7bec414 100644
--- a/tests/testthat/test-RunModel_Ungauged.R
+++ b/tests/testthat/test-RunModel_Ungauged.R
@@ -233,3 +233,59 @@ test_that("Donor node with diversion should work", {
   for(x in ls(e)) assign(x, get(x, e))
   expect_equal(OC_ref$`54032`$CritFinal, OutputsCalib$`54032`$CritFinal, tolerance = 1E-3)
 })
+
+test_that("Cemaneige with hysteresis works",  {
+  nodes <- loadSevernNodes()
+  nodes <- nodes[nodes$id %in% c("54057", "54032", "54001"), ]
+  nodes$model <- "RunModel_CemaNeigeGR4J"
+  nodes$model[nodes$id != 54057] <- "Ungauged"
+  griwrm <- CreateGRiwrm(nodes)
+
+  # # The custom ErrorCrit function !!!
+  ErrorCrit_KGE3 <- function(InputsCrit, OutputsModel, warnings = TRUE, verbose = TRUE) {
+    OutputsCritQ <- suppressMessages(
+      ErrorCrit_KGE2(InputsCrit, OutputsModel, warnings = TRUE, verbose = TRUE)
+    )
+    InputsCrit$Obs <- InputsCrit$SCA #a adapter
+    OutputsModel$Qsim <- OutputsModel$CemaNeigeLayers[[1]]$Gratio #a adapter
+    OutputsCritSCA <- suppressMessages(
+      ErrorCrit_KGE2(InputsCrit, OutputsModel, warnings = TRUE, verbose = TRUE)
+    )
+    OutputsCritQ$CritValue <-
+      (OutputsCritQ$CritValue + OutputsCritSCA$CritValue) / 2
+    OutputsCritQ$CritName <- "(0.5 * KGE2[Q] + 0.5 * KGE2[SCA])"
+    return(OutputsCritQ)
+  }
+  class(ErrorCrit_KGE3) <- c("FUN_CRIT", class(ErrorCrit_KGE3))
+
+  e <- suppressWarnings(
+    setupRunModel(griwrm = griwrm, runRunModel = FALSE, IsHyst = TRUE)
+  )
+  for(x in ls(e)) assign(x, get(x, e))
+
+  expect_true(all(sapply(InputsModel, function(x) x$model$hasX4)))
+
+  np <- getAllNodesProperties(griwrm)
+  InputsCrit <- CreateInputsCrit(
+    InputsModel,
+    FUN_CRIT = ErrorCrit_KGE3,
+    RunOptions = RunOptions,
+    Obs = Qobs[IndPeriod_Run, np$id[np$RunOff & np$calibration == "Gauged"], drop = FALSE],
+  )
+  InputsCrit$`54057`$SCA <- runif(length(IndPeriod_Run)) # Fake SCA
+  CalibOptions <- CreateCalibOptions(InputsModel)
+  CO <- lapply(CalibOptions, function(x) {
+    x$StartParamList <- matrix(
+      c(0.605,  320.596,   -0.042,   37.991,    2.221,    0.705,    6.764,   85.000,    0.850),
+      nrow = 1)
+    x$StartParamDistrib <- NULL
+    x
+  })
+  class(CO) <- class(CalibOptions)
+  e <- suppressWarnings(
+    runCalibration(nodes, InputsCrit = InputsCrit, CalibOptions = CO, IsHyst = TRUE)
+  )
+  for(x in ls(e)) assign(x, get(x, e))
+  expect_equal(sapply(Param, length),
+               c("54057" = 9, "54032" = 9, "54001" = 8))
+})