diff --git a/NAMESPACE b/NAMESPACE
index 4a6bcd8452fd510d24181e76f8b7c1d244578628..32655fdc89b910c2ae7be4f290d8ad87c5af7d12 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,7 +1,11 @@
 # Generated by roxygen2: do not edit by hand
 
-S3method(Calibration,default)
-S3method(Calibration,griwrm)
+S3method(Calibration,GriwrmInputsModel)
+S3method(Calibration,InputsModel)
+S3method(CreateCalibOptions,GriwrmInputsModel)
+S3method(CreateCalibOptions,InputsModel)
+S3method(CreateInputsCrit,GriwrmInputsModel)
+S3method(CreateInputsCrit,InputsModel)
 S3method(CreateInputsModel,Griwrm)
 S3method(CreateInputsModel,default)
 S3method(CreateRunOptions,GriwrmInputsModel)
@@ -10,6 +14,8 @@ S3method(RunModel,GriwrmInputsModel)
 S3method(RunModel,InputsModel)
 S3method(merge,Gits)
 export(Calibration)
+export(CreateCalibOptions)
+export(CreateInputsCrit)
 export(CreateInputsModel)
 export(CreateRunOptions)
 export(Ginet)
diff --git a/R/Calibration.GriwrmInputsModel.R b/R/Calibration.GriwrmInputsModel.R
new file mode 100644
index 0000000000000000000000000000000000000000..e580fe847801b99e3874a2ed68fb7ea09d4dca06
--- /dev/null
+++ b/R/Calibration.GriwrmInputsModel.R
@@ -0,0 +1,56 @@
+#' Calibration of a semi-distributed run-off model
+#'
+#' @param InputsModel object of class \emph{GriwrmInputsModel}, see \code{\link{CreateInputsModel.Griwrm}} for details.
+#' @param RunOptions object of class \emph{GriwrmRunOptions}, see \code{\link{CreateRunOptiosn.Griwrm}} for details.
+#' @param InputsCrit object of class \emph{GriwrmInputsCrit}, see \code{\link{CreateInputsCrit.Griwrm}} for details.
+#' @param CalibOptions object of class \emph{GriwrmCalibOptions}, see \code{\link{CreateCalibOptions.Griwrm}} for details.
+#' @param useUpstreamQsim boolean describing if simulated (\code{TRUE}) or observed (\code{FALSE}) flows are used for calibration. Default is \code{TRUE}.
+#' @param verbose (optional) boolean indicating if the function is run in verbose mode or not, default = \code{TRUE}
+#' @param ... further arguments passed to \code{\link[airGR]{Calibration}}.
+#'
+#' @return GriwrmOutputsCalib object which is a list of OutputsCalib (See \code{\link[airGR]{Calibration}}) for each node of the semi-distributed model.
+#' @export
+Calibration.GriwrmInputsModel <- function(InputsModel,
+                                          RunOptions,
+                                          InputsCrit,
+                                          CalibOptions,
+                                          useUpstreamQsim = TRUE,
+                                          verbose = TRUE,
+                                          ...) {
+
+  OutputsCalib <- list()
+  class(OutputsCalib) <- append(class(OutputsCalib), "GriwrmOutputsCalib")
+
+  OutputsModel <- list()
+  class(OutputsModel) <- append(class(OutputsModel), "GriwrmOutputsModel")
+
+  for(IM in InputsModel) {
+    if(verbose) cat("Calibration.GriwrmInputsModel: Treating sub-basin", IM$id, "...\n")
+
+    if(useUpstreamQsim) {
+      # Update InputsModel$QobsUpstr with simulated upstream flows
+      IM <- UpdateQsimUpstream(IM, OutputsModel)
+    }
+
+    OutputsCalib[[IM$id]] <- Calibration.InputsModel(
+      InputsModel = IM,
+      RunOptions = RunOptions[[IM$id]],
+      InputsCrit = InputsCrit[[IM$id]],
+      CalibOptions = CalibOptions[[IM$id]],
+      ...
+    )
+
+    if(useUpstreamQsim) {
+      # Run the model for the sub-basin
+      OutputsModel[[IM$id]] <- RunModel(
+        InputsModel = IM,
+        RunOptions = RunOptions[[IM$id]],
+        Param = OutputsCalib[[IM$id]]$ParamFinalR
+      )
+    }
+
+  }
+
+  return(OutputsCalib)
+
+}
diff --git a/R/Calibration.InputsModel.R b/R/Calibration.InputsModel.R
new file mode 100644
index 0000000000000000000000000000000000000000..6520ab81cf8716f89c4cba8f85841b8ff680e188
--- /dev/null
+++ b/R/Calibration.InputsModel.R
@@ -0,0 +1,10 @@
+#' Wrapper to \code{\link[airGR]{Calibration}}.
+#'
+#' @param InputsModel object of class \emph{InputsModel}, see \code{\link[airGR]{CreateInputsModel}} for details.
+#' @param ... further arguments passed to \code{\link[airGR]{Calibration}}.
+#'
+#' @return \emph{CalibOutput} object.
+#' @export
+Calibration.InputsModel <- function(InputsModel, ...) {
+  airGR::Calibration(InputsModel, FUN_MOD = InputsModel$FUN_MOD, ...)
+}
diff --git a/R/Calibration.R b/R/Calibration.R
new file mode 100644
index 0000000000000000000000000000000000000000..04b76e1e56aa70fc691a405b93f88f42033b59dd
--- /dev/null
+++ b/R/Calibration.R
@@ -0,0 +1,10 @@
+#' Calibration of either airGR model and GRIWRM semi-distributive model
+#'
+#' @param InputsModel the class of the first parameter determine which calibration is used
+#' @param ... further arguments passed to or from other methods.
+#'
+#' @return \emph{OutputsCalib} or \emph{GriwrmOutputsCalib} object
+#' @export
+Calibration <- function(InputsModel, ...) {
+  UseMethod("Calibration", InputsModel)
+}
diff --git a/R/CreateCalibOptions.GriwrmInputsModel.R b/R/CreateCalibOptions.GriwrmInputsModel.R
new file mode 100644
index 0000000000000000000000000000000000000000..e92e48e864b996269cced2ecd2f4e9b8bb094552
--- /dev/null
+++ b/R/CreateCalibOptions.GriwrmInputsModel.R
@@ -0,0 +1,19 @@
+#' Title
+#'
+#' @param InputsModel object of class \emph{GriwrmInputsModel}, see \code{\link{CreateInputsModel.Griwrm}} for details.
+#' @param ... further arguments passed to \code{\link[airGR]{CreateCalibOptions}}.
+#'
+#' @return \emph{GriwrmCalibOptions} object.
+#' @export
+CreateCalibOptions.GriwrmInputsModel <- function(InputsModel, ...) {
+
+  CalibOptions <- list()
+
+  for(IM in InputsModel) {
+    CalibOptions[[IM$id]] <- CreateCalibOptions.InputsModel(
+      InputsModel = IM,
+      ...
+    )
+  }
+  return(CalibOptions)
+}
diff --git a/R/CreateCalibOptions.InputsModel.R b/R/CreateCalibOptions.InputsModel.R
new file mode 100644
index 0000000000000000000000000000000000000000..0099cf7f2ca852132208af0a859dca71d83a9ef0
--- /dev/null
+++ b/R/CreateCalibOptions.InputsModel.R
@@ -0,0 +1,15 @@
+#' Wrapper to \code{\link[airGR]{CreateCalibOptions}}
+#'
+#' @param InputsModel object of class \emph{InputsModel}, see \code{\link[airGR]{CreateInputsModel}} for details.
+#' @param ... further arguments passed to \code{\link[airGR]{CreateCalibOptions}}.
+#'
+#' @return \emph{CalibOptions} object.
+#' @export
+CreateCalibOptions.InputsModel <- function(InputsModel,
+                               ...) {
+  airGR::CreateCalibOptions(
+    FUN_MOD = InputsModel$FUN_MOD,
+    IsSD = !is.null(InputsModel$QobsUpstr),
+    ...
+  )
+}
diff --git a/R/CreateCalibOptions.R b/R/CreateCalibOptions.R
new file mode 100644
index 0000000000000000000000000000000000000000..4ef9311aa6605e5b0fd9845cb33ba7b888dc46c4
--- /dev/null
+++ b/R/CreateCalibOptions.R
@@ -0,0 +1,10 @@
+#' CreateCalibOptions both available for \emph{InputsModel} and \emph{GrwirmInputsModel} objects
+#'
+#' @param InputsModel object of class \emph{InputsModel}, see \code{\link[airGR]{CreateInputsModel}} for details.
+#' @param ... further arguments passed to or from other methods.
+#'
+#' @return
+#' @export
+CreateCalibOptions <- function(InputsModel, ...) {
+  UseMethod("CreateCalibOptions", InputsModel)
+}
diff --git a/R/CreateInputsCrit.GriwrmInputsModel.R b/R/CreateInputsCrit.GriwrmInputsModel.R
new file mode 100644
index 0000000000000000000000000000000000000000..db1769fd458dfcddfdbbac1f8cae75023cc8e282
--- /dev/null
+++ b/R/CreateInputsCrit.GriwrmInputsModel.R
@@ -0,0 +1,29 @@
+#' Create \emph{GriwrmInputsCrit} object for GR-IWRM.
+#' @param InputsModel  object of class \emph{GriwrmInputsModel}, see \code{\link{CreateInputsModel.Griwrm}} for details.
+#' @param FUN_CRIT \[function (atomic or list)\] error criterion function (e.g. \code{\link[airGR]{ErrorCrit_RMSE}}, \code{\link[airGR]{ErrorCrit_NSE}})
+#' @param RunOptions object of class \emph{GriwrmRunOptions}, see \code{[CreateRunOptions.Griwrm]} for details.
+#' @param gits object of class \emph{Gits}, see [Gits].
+#' @param ... further arguments passed to \code{\link[airGR]{CreateInputsCrit}}.
+#'
+#' @return Object of class \emph{GriwrmInputsCrit}
+#' @export
+CreateInputsCrit.GriwrmInputsModel <- function(InputsModel,
+                                               FUN_CRIT = airGR::ErrorCrit_NSE,
+                                               RunOptions,
+                                               gits,
+                                               ...) {
+  InputsCrit <- list()
+  class(InputsCrit) <- append(class(InputsCrit), "GriwrmInputsCrit")
+
+  for(IM in InputsModel) {
+    InputsCrit[[IM$id]] <- CreateInputsCrit.InputsModel(
+      InputsModel = IM,
+      FUN_CRIT = FUN_CRIT,
+      RunOptions = RunOptions[[IM$id]],
+      Obs = gits[[IM$id]]$Qobs[RunOptions[[IM$id]]$IndPeriod_Run],
+      ...
+    )
+  }
+
+  return(InputsCrit)
+}
diff --git a/R/CreateInputsCrit.InputsModel.R b/R/CreateInputsCrit.InputsModel.R
new file mode 100644
index 0000000000000000000000000000000000000000..f1a337bd590af5facae220e6f70861badd5664d4
--- /dev/null
+++ b/R/CreateInputsCrit.InputsModel.R
@@ -0,0 +1,16 @@
+#' Wrapper to \code{\link[airGR]{CreateInputsCrit}}
+#'
+#' @param InputsModel object of class \emph{InputsModel}, see \code{\link[airGR]{CreateInputsModel}} for details.
+#' @param FUN_CRIT \[function (atomic or list)\] error criterion function (e.g. \code{\link[airGR]{ErrorCrit_RMSE}}, \code{\link[airGR]{ErrorCrit_NSE}})
+#' @param ... further arguments passed to \code{\link[airGR]{CreateInputsCrit}}
+#'
+#' @return object of class \emph{InputsCrit} containing the data required to evaluate the model outputs. See \code{\link[airGR]{CreateInputsCrit}}
+#' @export
+CreateInputsCrit.InputsModel <- function(InputsModel,
+                                         FUN_CRIT,
+                                         ...) {
+
+  airGR::CreateInputsCrit(FUN_CRIT = FUN_CRIT,
+                          InputsModel = InputsModel,
+                          ...)
+}
diff --git a/R/CreateInputsCrit.R b/R/CreateInputsCrit.R
new file mode 100644
index 0000000000000000000000000000000000000000..bce0108f78145a512635a6a6e0c6ebccbfcddb28
--- /dev/null
+++ b/R/CreateInputsCrit.R
@@ -0,0 +1,10 @@
+#' Title
+#'
+#' @param InputsModel InputsModel for GR-IWRM (See \code{[CreateInputsModel.Griwrm]}) or AirGR (See \code{\link[airGR]{CreateInputsModel}})
+#' @param ... further arguments passed to or from other methods.
+#'
+#' @return
+#' @export
+CreateInputsCrit <- function(InputsModel, ...) {
+  UseMethod("CreateInputsCrit", InputsModel)
+}
diff --git a/R/CreateInputsModel.Griwrm.R b/R/CreateInputsModel.Griwrm.R
index 96e0c852920950090ae85056e86834366df29c49..52ddce9f6657da2d6b74b715894e796debea7536 100644
--- a/R/CreateInputsModel.Griwrm.R
+++ b/R/CreateInputsModel.Griwrm.R
@@ -8,7 +8,7 @@
 #'
 #' @return GriwrmInputsModel object equivalent to airGR InputsModel object for a semi-distributed model (See \code{\link[airGR]{CreateInputsModel}})
 #' @export
-CreateInputsModel.Griwrm <- function(x, girop, gits, verbose = TRUE,...) {
+CreateInputsModel.Griwrm <- function(x, girop, gits, verbose = TRUE, ...) {
 
   InputsModel <- CreateEmptyGriwrmInputsModel()
 
diff --git a/R/UpdateQsimUpstream.R b/R/UpdateQsimUpstream.R
index 560984ac03f20153f9a27cc03afea5149b1e85ef..2bccce8204e1c5f72e8a9e8d0c957705acefcdeb 100644
--- a/R/UpdateQsimUpstream.R
+++ b/R/UpdateQsimUpstream.R
@@ -1,19 +1,19 @@
 #' Update InputsModel$QobsUpstr with simulated upstream flows provided by GriwrmOutputsModels object.
 #'
 #' @param InputsModel \emph{GriwrmInputsModel} object. See \code{[CreateInputsModel.Griwrm]}.
-#' @param OutputsModels \emph{GriwrmOutputsModel} object provided by \code{[RunModel.GriwrmInputsModel]}.
+#' @param OutputsModel \emph{GriwrmOutputsModel} object provided by \code{[RunModel.GriwrmInputsModel]}.
 #'
 #' @description This function is used by \code{\link{RunModel.GriwrmInputsModel}} and \code{\link{Calibration.GriwrmInputsModel}} in order to provide upstream simulated flows to a node.
 #'
 #' @return InputsModel object with updated QobsUpsr
 #'
-UpdateQsimUpstream <- function(InputsModel, OutputsModels) {
+UpdateQsimUpstream <- function(InputsModel, OutputsModel) {
   if(length(InputsModel$UpstreamNodes) > 0) {
     for(i in 1:length(InputsModel$UpstreamNodes)) {
       QobsUpstr1 <- matrix(
         c(
           rep(0, length(RunOptions[[InputsModel$id]]$IndPeriod_WarmUp)),
-          OutputsModels[[InputsModel$UpstreamNodes[i]]]$Qsim
+          OutputsModel[[InputsModel$UpstreamNodes[i]]]$Qsim
         ), ncol = 1
       )
       if(i == 1) {
diff --git a/vignettes/V01_First_network.Rmd b/vignettes/V01_First_network.Rmd
index d2fc99f550778aff4c65b7c931938aa65f1bed47..f834388dfa8a949ef07cbc104ed7faedb4e1cde4 100644
--- a/vignettes/V01_First_network.Rmd
+++ b/vignettes/V01_First_network.Rmd
@@ -130,6 +130,6 @@ InputsModel <- CreateInputsModel(ginet, girop, gits)
 
 ```{r}
 dir.create("_cache", showWarnings = FALSE)
-save(ginet, girop, gits, InputsModel, file = "_cache/seine.RData")
+save(ginet, girop, gits, InputsModel, file = "_cache/V01.RData")
 ```
 
diff --git a/vignettes/V03_First_Calibration.Rmd b/vignettes/V03_First_Calibration.Rmd
new file mode 100644
index 0000000000000000000000000000000000000000..7095a114aa5c19e5721063b9a43412195e5640ce
--- /dev/null
+++ b/vignettes/V03_First_Calibration.Rmd
@@ -0,0 +1,46 @@
+---
+title: "03_First_Calibration"
+author: "David Dorchies"
+vignette: >
+  %\VignetteIndexEntry{Calibration of naturalised semi-distributive model}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r setup, include=FALSE}
+knitr::opts_chunk$set(echo = TRUE)
+```
+
+## Loading network and time series data
+
+Run `vignette("01_First_network", package = "griwrm")` and `vignette("02_First_run", package = "griwrm")` before this one in order to create the Rdata files loaded below:
+
+```{r}
+load("_cache/V01.RData")
+load("_cache/V02.RData")
+```
+
+## InputsCrit object
+
+```{r cars}
+InputsCrit <- CreateInputsCrit(
+  InputsModel = InputsModel, 
+  RunOptions = RunOptions, gits = gits
+)
+str(InputsCrit)
+```
+
+## GriwrmCalibOptions object
+
+```{r, eval=FALSE}
+CalibOptions <- CreateCalibOptions(InputsModel)
+str(CalibOptions)
+```
+
+## Calibration
+
+```{r}
+OutputsCalib <- Calibration(InputsModel, RunOptions, InputsCrit, CalibOptions)
+```
+
+
diff --git a/vignettes/v02_First_run.Rmd b/vignettes/v02_First_run.Rmd
index d65efb7763203774fe370484299adaa72c4e0b42..ae3050f458663e97f847d489e5e096e0b490db0a 100644
--- a/vignettes/v02_First_run.Rmd
+++ b/vignettes/v02_First_run.Rmd
@@ -25,7 +25,7 @@ library(griwrm)
 Run `vignette("01_First_network", package = "griwrm")` before this one in order to create the Rdata file loaded below:
 
 ```{r}
-load("_cache/seine.RData")
+load("_cache/V01.RData")
 ```
 
 ### Loading 
@@ -111,6 +111,12 @@ OutputsModels <- RunModel(
 )
 ```
 
+## Save data for next vignettes
+
+```{r}
+save(RunOptions, file = "_cache/V02.RData")
+```
+
 ## Plot the result for each basin
 
 ```{r, fig.height = 5, fig.width = 8}