diff --git a/DESCRIPTION b/DESCRIPTION
index f07d184eb2013b489db8a4a9195027486454c4ba..2fbd176abba139123b0471e68aa94e001da912c5 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,7 +1,7 @@
 Package: CropWat
 Type: Package
 Title: R Implementation of the FAO CropWat Model
-Version: 0.1.0
+Version: 0.1.0.9000
 Authors@R: c(
     person("David", "Dorchies", , "david.dorchies@inrae.fr", role = c("aut", "cre"),
            comment = c(ORCID = "0000-0002-6595-7984")),
@@ -21,7 +21,8 @@ RoxygenNote: 7.3.2
 Roxygen: list(markdown = TRUE)
 Suggests:
     knitr,
-    rmarkdown
+    rmarkdown,
+    testthat (>= 3.0.0)
 VignetteBuilder: knitr
 Imports:
     dplyr,
@@ -29,7 +30,9 @@ Imports:
     lubridate,
     readr,
     rlang,
+    stats,
     tibble,
     tidyr
 Depends:
     R (>= 2.10)
+Config/testthat/edition: 3
diff --git a/R/CW_create_input.R b/R/CW_create_input.R
index 382b03428a8b78bc74de0b084e182f246aea8d07..9e67d4ed671f0df9a7da85f638c7f0ae5043e0a3 100644
--- a/R/CW_create_input.R
+++ b/R/CW_create_input.R
@@ -1,5 +1,10 @@
 #' Create CropWat model input
 #'
+#' @details
+#' The crop cycle begins at the first matching sowing date in the simulation
+#' period. So, first time steps of simulation if are not in a crop cycle even
+#' if they occur during the crop cycle.
+#'
 #' @inheritParams get_crop_params
 #' @inheritParams calc_TAW
 #' @param DatesR Simulation period ([vector] of [Date])
@@ -13,9 +18,9 @@
 #' # Import example climate dataset
 #' data(ZH_3_clim)
 #' str(ZH_3_clim)
-#' # Selecting year 2010
+#' # Selecting years 2010 and 2011
 #' meteo <-
-#'   ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") & ZH_3_clim$Date <= as.Date("2010-12-31"), ]
+#'   ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") & ZH_3_clim$Date <= as.Date("2011-12-31"), ]
 #' # Create model input
 #' cw_input <- CW_create_input("SB2023-soja",
 #'                             DatesR = meteo$Date,
@@ -28,34 +33,48 @@
 #' plot(cw_input)
 #'
 CW_create_input <- function(crop,
-                            year,
-                            DatesR = seq(as.Date(paste0(year, "-01-01")), as.Date(paste0(year, "-12-31")), by = "1 day"),
+                            DatesR,
                             ETo,
                             P,
                             soil_depth,
                             AWC,
                             cp = get_crop_params(crop),
                             sowing_date = cp$sowing_date) {
-  year <- lubridate::year(DatesR[1])
-  Kc <- calc_Kc(cp, year = year, sowing_date = sowing_date)
-  isCycle <- calc_isCycle(cp, year = year, sowing_date = sowing_date)
-  Zr <- calc_root_depth(cp,
-                        soil_depth,
-                        year,
-                        sowing_date)
-  TAW <- calc_TAW(cp, AWC, soil_depth, year, sowing_date)
-  p <- calc_p(cp, year, sowing_date)
-  cw_input <- tibble(
-    DatesR = DatesR,
-    isCycle = isCycle,
-    P = P,
-    Kc = Kc,
-    Zr = Zr,
-    ETc = Kc * ETo,
-    p = p,
-    TAW = TAW,
-    RAW = calc_RAW(TAW, p)
-  )
+
+  cycles <- get_yearly_cycles(DatesR)
+
+  l <- lapply(cycles, function(cycle) {
+    dates <- cycle$dates
+    Kc <- calc_Kc(cp, DatesR = dates, sowing_date = sowing_date)
+    isCycle <- calc_isCycle(cp, DatesR = dates, sowing_date = sowing_date)
+    Zr <- calc_root_depth(
+      cp,
+      soil_depth = soil_depth,
+      DatesR = dates,
+      sowing_date = sowing_date
+    )
+    TAW <- calc_TAW(
+      cp,
+      AWC = AWC,
+      soil_depth = soil_depth,
+      DatesR = dates,
+      sowing_date = sowing_date,
+      root_depth = Zr
+    )
+    p <- calc_p(cp, dates, sowing_date)
+    cw_input <- tibble(
+      DatesR = dates,
+      isCycle = isCycle,
+      P = P[cycle$which],
+      Kc = Kc,
+      Zr = Zr,
+      ETc = Kc * ETo[cycle$which],
+      p = p,
+      TAW = TAW,
+      RAW = calc_RAW(TAW, p)
+    )
+  })
+  cw_input <- bind_rows(l)
   attr(cw_input, "crop_params") <- cp
   attr(cw_input, "soil_params") <- list(soil_depth = soil_depth, AWC = AWC)
   class(cw_input) <- c("CW_input", "CW_TS", class(cw_input))
diff --git a/R/CW_model.R b/R/CW_model.R
index d56564e1ae075eb86077ee8787e73fe9c8c19951..351a836886e442c00a5fc9bf6f114a5b43c79e55 100644
--- a/R/CW_model.R
+++ b/R/CW_model.R
@@ -27,13 +27,13 @@
 CW_model <- function(X, input, FUN_IRRIG = CW_irrig_Dr) {
   Dr <- X$Dr
 
-  if (input$isCycle == 0 && X$isCycle == 1) {
-    # TODO Check what does that mean
+  if (!input$isCycle && X$isCycle) {
+    # What happens during the harvest day?
     Dr <- Dr * input$TAW / X$TAW - input$P # ???
   }
   Dr <- max(0, Dr - input$P)
 
-  if (Dr > input$RAW) {
+  if (input$isCycle && Dr > input$RAW) {
     Ks <- max(0, (input$TAW - Dr) / (input$TAW - input$RAW))
   } else {
     Ks <- 1
diff --git a/R/calc_Kc.R b/R/calc_Kc.R
index cc413ddf9a0abb592c21e2166703b8eb82e8a345..202e2b0cde9dad95803e85d319c8b61006736796 100644
--- a/R/calc_Kc.R
+++ b/R/calc_Kc.R
@@ -1,37 +1,60 @@
-#' Compute crop coefficient time series for one crop cycle or calendar year
+#' Compute crop parameters time series from crop parameters pivot points
+#'
+#' These functions compute the following parameters:
+#'
+#' - `Calc_Kc`: crop coefficient $K_c$
+#' - `calc_p`: critical depletion fraction $p=RAW/TAW$
+#' - `calc_root_depth`: root depth in m
+#' - `calc_RAW`: Readily Available Water (RAW) in mm
+#' - `calc_TAW`:  Total Available Water (TAW) in mm
 #'
 #' @param cp Crop parameters (See [get_crop_params])
-#' @param year Year of simulation (Only used for detecting leap year).
+#' @param AWC Available Water Capacity (mm)
+#' @param soil_depth Soil depth (m)
+#' @param root_depth Root depth time series (m). See [calc_root_depth]
+#' @param TAW Total Available Water (mm). See [calc_TAW]
+#' @param p fraction of Readily Available Water time series. See [calc_p]
+#' @param DatesR A [vector] of continuous [Date]
 #' If `NULL`, the calculation is limited to the crop cycle of the plant
 #' @param sowing_date Sowing date in format "MM-DD"
 #'
-#' @return A [vector] of Kc for each day of the year or the crop cycle.
+#' @return A [vector] of the parameter for each day of the crop cycle or the period defined by `DatesR`.
+#'
+#' @details
+#' For `calc_TAW`, parameters `cp`, `year`, and `sowing_date` are useless if `root_depth` is
+#' provided.
+#'
+#'
 #' @export
+#' @rdname calc_params
 #'
 #' @examples
-#' Kc <- calc_Kc(get_crop_params("SB2023-soja"), year = NULL)
+#' # Compute Kc for the crop cycle
+#' Kc <- calc_Kc(get_crop_params("SB2023-soja"))
 #' plot(Kc, type = "l")
 #'
-#' Kc <- calc_Kc(get_crop_params("SB2023-soja"), year = 2024)
+#' # Compute Kc for a given period (less than one year)
+#' # with default sowing date defined in crop parameters
+#' DatesR <- seq(as.Date("2010-03-01"), as.Date("2010-10-31"), by = "1 day")
+#' Kc <- calc_Kc(get_crop_params("SB2023-soja"), DatesR = DatesR)
 #' plot(Kc, type = "l")
 #'
+#' # Compute Kc for a given period with user defined sowing date
+#' Kc <- calc_Kc(get_crop_params("FAO-MAIZE"),
+#'               DatesR = DatesR,
+#'               sowing_date = "05-01")
+#' plot(Kc, type = "l")
 calc_Kc <- function(cp,
-                    year,
+                    DatesR = NULL,
                     sowing_date = cp$sowing_date) {
-
   # TODO: stopifnot cp, year, sowing_date format
 
-  kc <- c(
-    rep(cp$Kini, cp$Lini),
-    cp$Kini + ((0:(cp$Ldev - 1)) / (cp$Ldev)) * (cp$Kmax -
-                                                   cp$Kini),
-    #pb dernière valeur égale à Kc_mid, 1 j trop tôt
-    rep(cp$Kmax, cp$Lmid),
-    cp$Kmax + ((1:cp$Lend) / cp$Lend) * (cp$Kend - cp$Kmax)
+  calc_interpolated_param(
+    DatesR,
+    sowing_date,
+    x = c(cp$Lini, cp$Ldev, cp$Lmid, cp$Lend),
+    y = c(cp$Kini, cp$Kmax, cp$Kmax, cp$Kend),
+    yleft = cp$Kini,
+    yright = cp$Kini
   )
-
-  if (!is.null(year)) {
-    kc <- complete_year(kc, year, sowing_date)
-  }
-  return(kc)
 }
diff --git a/R/calc_RAW.R b/R/calc_RAW.R
index 180f2bb905d8c818446973f715e793ff39653568..64ce44ccc65788332c062bc3454307e3138c50f6 100644
--- a/R/calc_RAW.R
+++ b/R/calc_RAW.R
@@ -1,20 +1,5 @@
-#' Calculation of Readily Available Water (RAW)
-#'
-#' @param TAW Total Available Water (mm). See [calc_TAW]
-#' @param p fraction of Readily Available Water time series. See [calc_p]
-#'
-#' @return A [vector] of Readily Available Water.
 #' @export
-#'
-#' @examples
-#' cp <- get_crop_params("SB2023-soja")
-#' TAW <- calc_TAW(cp,
-#'                 AWC = 140,
-#'                 soil_depth = 1.2,
-#'                 year = 2024)
-#' p <- calc_p(cp, year = 2024)
-#' RAW <- calc_RAW(TAW, p)
-#' plot(RAW, type = "l")
+#' @rdname calc_params
 calc_RAW <- function(TAW, p) {
   return(p * TAW)
 }
diff --git a/R/calc_TAW.R b/R/calc_TAW.R
index 54e60612fc550ff9ec9f0c794f6eaaaabb82084f..c15c724fe3feac8c824f8fae3a406bd63c5a2126 100644
--- a/R/calc_TAW.R
+++ b/R/calc_TAW.R
@@ -1,29 +1,11 @@
-#' Calculation of Total Available Water (TAW)
-#'
-#' @details
-#' Parameters `cp`, `year`, and `sowing_date` are useless if `root_depth` is
-#' provided.
-#'
-#' @inheritParams calc_root_depth
-#' @param AWC Available Water Capacity (mm)
-#' @param root_depth Root depth time series (m). See [calc_root_depth].
-#'
-#' @return A [vector] of Total Available Water (mm) for each day of the year or the crop cycle.
 #' @export
-#'
-#' @examples
-#' TAW <- calc_TAW(get_crop_params("SB2023-soja"),
-#'                 AWC = 140,
-#'                 soil_depth = 1.2,
-#'                 year = 2024)
-#' plot(TAW, type = "l")
-#'
+#' @rdname calc_params
 calc_TAW <- function(cp,
                      AWC,
                      soil_depth,
-                     year,
+                     DatesR = NULL,
                      sowing_date = cp$sowing_date,
-                     root_depth = calc_root_depth(cp, soil_depth, year, sowing_date)) {
+                     root_depth = calc_root_depth(cp, soil_depth, DatesR, sowing_date)) {
 
   return(AWC / soil_depth * root_depth)
 }
diff --git a/R/calc_isCycle.R b/R/calc_isCycle.R
index 3fbd390e51653ad1a17583ed8b582d901f07b182..ec4482973b1f03009ecc12b8533d3794d295bfc2 100644
--- a/R/calc_isCycle.R
+++ b/R/calc_isCycle.R
@@ -6,12 +6,15 @@
 #' @export
 #'
 #' @examples
-#' isCycle <- calc_isCycle(get_crop_params("SB2023-soja"), year = 2024)
+#' DatesR <- seq(as.Date("2010-03-01"), as.Date("2010-10-31"), by = "1 day")
+#' isCycle <- calc_isCycle(get_crop_params("SB2023-soja"), DatesR)
+#' plot(isCycle)
 #'
-calc_isCycle <- function(cp, year, sowing_date = cp$sowing_date) {
-  isCycle <- rep(TRUE, cp$Lini + cp$Ldev + cp$Lmid + cp$Lend)
-  if (!is.null(year)) {
-    isCycle <- complete_year(isCycle, year, sowing_date)
-  }
+calc_isCycle <- function(cp, DatesR, sowing_date = cp$sowing_date) {
+  Ltot <-  c(cp$Lini, cp$Ldev, cp$Lmid, cp$Lend)
+  l <- get_period(DatesR, sowing_date, Ltot)
+  isCycle <- c(rep(FALSE, l$doy_start),
+               rep(TRUE, sum(Ltot)),
+               rep(FALSE, max(0, length(DatesR) - sum(Ltot) - l$doy_start)))
   return(isCycle)
 }
diff --git a/R/calc_p.R b/R/calc_p.R
index 1a68c483dc4951f41e05278c881b917e67d763d3..775183ef9e1e303c9d6c3fd9325353b6aecee298 100644
--- a/R/calc_p.R
+++ b/R/calc_p.R
@@ -1,30 +1,14 @@
-#' Compute critical depletion fraction (p) time series for one crop cycle or calendar year
-#'
-#' *p* is the fraction RAW / TAW
-#'
-#' @inheritParams calc_Kc
-#'
-#' @return A [vector] of critical depletion fraction for each day of the year or the crop cycle.
 #' @export
-#'
-#' @examples
-#' p <- calc_p(get_crop_params("SB2023-soja"),
-#'                       year = 2024)
-#' plot(p, type = "l")
-#'
+#' @rdname calc_params
 calc_p <- function(cp,
-                   year,
+                   DatesR = NULL,
                    sowing_date = cp$sowing_date) {
-  p <- c(
-    cp$p_ini + (0:(cp$Lini + cp$Ldev - 1
-    )) * (cp$p_mid - cp$p_ini) / (cp$Lini + cp$Ldev - 1)
-    ,
-    rep(cp$p_mid, cp$Lmid)
-    ,
-    cp$p_mid + (1:(cp$Lend)) * (cp$p_end - cp$p_mid) / (cp$Lend)
+  calc_interpolated_param(
+    DatesR,
+    sowing_date,
+    x = c(1, cp$Lini + cp$Ldev - 1, cp$Lmid, cp$Lend),
+    y = c(cp$p_ini, cp$p_mid, cp$p_mid, cp$p_end),
+    yleft = cp$p_ini,
+    yright = cp$p_ini
   )
-  if (!is.null(year)) {
-    p <- complete_year(p, year, sowing_date)
-  }
-  return(p)
 }
diff --git a/R/calc_root_depth.R b/R/calc_root_depth.R
index 88965a9621ce9213b4edb2e66313ac6c67b7d3be..15d8a5a13b3777cd8e779fce2bad62cfb4e2c8f4 100644
--- a/R/calc_root_depth.R
+++ b/R/calc_root_depth.R
@@ -1,30 +1,17 @@
-#' Compute root depth time series for one crop cycle or calendar year
-#'
-#' @inheritParams calc_Kc
-#' @param soil_depth Soil depth (m)
-#'
-#' @return A [vector] of root depth (m) for each day of the year or the crop cycle.
 #' @export
-#'
-#' @examples
-#' Zr <- calc_root_depth(get_crop_params("SB2023-soja"),
-#'                       soil_depth = 1.2,
-#'                       year = 2024)
-#' plot(Zr, type = "l")
-#'
+#' @rdname calc_params
 calc_root_depth <- function(cp,
                             soil_depth,
-                            year,
+                            DatesR = NULL,
                             sowing_date = cp$sowing_date) {
-  Zr <- c(cp$Zini + (0:(cp$Lini + cp$Ldev - 1) / (cp$Lini + cp$Ldev)) * (cp$Zend - cp$Zini),
-          rep(cp$Zend, cp$Lmid + cp$Lend))
-
-  if (!is.null(year)) {
-    Zr <- complete_year(Zr, year, sowing_date)
-  }
-
-  # Root depth is limited by soil depth
-  Zr[Zr > soil_depth] <- soil_depth
-
-  return(Zr)
+  Zini <- min(cp$Zini, soil_depth)
+  Zend <- min(cp$Zend, soil_depth)
+  calc_interpolated_param(
+    DatesR,
+    sowing_date,
+    x = c(1, cp$Lini + cp$Ldev - 1, cp$Lmid + cp$Lend),
+    y = c(Zini, Zend, Zend),
+    yleft = cp$Zini,
+    yright = cp$Zini
+  )
 }
diff --git a/R/utils.R b/R/utils.R
index f6f612e72be6f5f3c5d506ac0b9df69c77ae681e..21b3a2aeeda305d122a43499be37b61bb093d96c 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -12,11 +12,42 @@ CW_data <- function(file) {
   system.file("extdata", file, package = "CropWat")
 }
 
-complete_year <- function(x, year, sowing_date) {
-  # Cycle starting day (DOY)
-  doy_start <- julian(as.Date(paste0(year, "-", sowing_date)), origin = as.Date(paste0(year, "-01-01"))) + 1
-  nb_days_year <- ifelse(lubridate::leap_year(year), 366, 365)
-  x_year <- rep(ifelse(is.logical(x), FALSE, x[1]), nb_days_year)
-  x_year[doy_start:(doy_start + length(x) - 1)] <- x
-  return(x_year)
+calc_interpolated_param <- function(DatesR, sowing_date, x, y, yleft, yright) {
+  l <- get_period(DatesR, sowing_date, x)
+  stats::approx(x = l$doy_start + cumsum(x), y = y, xout = l$xout, yleft = yleft, yright = yright)$y
+}
+
+get_period <- function(DatesR, sowing_date, x) {
+  if (!is.null(DatesR)) {
+    stopifnot(inherits(DatesR, 'Date'),
+              DatesR[length(DatesR)] <= DatesR[1] + lubridate::years(),
+              !is.na(sowing_date),
+              grepl("^[0-9]{1,2}-[0-9]{1,2}$", sowing_date))
+    year <- lubridate::year(DatesR[1])
+    doy_start <- julian(as.Date(paste0(year, "-", sowing_date)), origin = DatesR[1])
+    xout <- seq_along(DatesR)
+  } else {
+    doy_start <- 0
+    xout <- seq(sum(x))
+  }
+  return(list(doy_start = doy_start, xout = xout))
+}
+
+get_yearly_cycles <- function(DatesR) {
+  years <- unique(lubridate::year(DatesR))
+  start_dates <- rep(DatesR[1], length(years))
+  lubridate::year(start_dates) <- years
+  end_dates <- start_dates - lubridate::days() + lubridate::years()
+  end_dates[length(end_dates)] <- last(DatesR)
+  if (last(end_dates) <= last(start_dates)) {
+    years <- years[- length(years)]
+  }
+  lapply(setNames(seq_along(years), years), function(i) {
+    dates <- seq(start_dates[i], end_dates[i], by = "1 day")
+    list(year = years[i],
+         start = start_dates[i],
+         end = end_dates[i],
+         dates = dates,
+         which = which(DatesR %in% dates))
+  })
 }
diff --git a/README.Rmd b/README.Rmd
index 4a1c5a5e4a82bebed246792d3dfe5dda4a699060..ddef6396e2823a25f7757efe029fe195f36a7646 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -17,6 +17,7 @@ knitr::opts_chunk$set(
 # CropWat
 
 <!-- badges: start -->
+
 <!-- badges: end -->
 
 CropWat is an R Implementation of the FAO CropWat Model.
@@ -43,13 +44,14 @@ irrigated crop.
 ```{r example}
 # Load library
 library(CropWat)
+library(dplyr)
 
 # Import example climate dataset
 data(ZH_3_clim)
 
 # Selecting year 2010
 meteo <- ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") &
-                   ZH_3_clim$Date <= as.Date("2010-12-31"), ]
+                   ZH_3_clim$Date <= as.Date("2014-12-31"), ]
 
 # Formatting model input
 cw_input <- CW_create_input("SB2023-soja",
@@ -65,13 +67,13 @@ X <- CW_create_state(cw_input = cw_input)
 
 # Choose an irrigation management
 # Example: Fill Soil moisture depletion when half of RAW is reached
-fun_irrig_half_RAW <- CW_irrig_fun_factory(RAW_ratio = 0.5, apply_Dr = TRUE)
+fun_irrig_half_RAW <- CW_irrig_fun_factory(RAW_ratio = 1.25, apply_Dr = TRUE)
 
 # Simulate water balance with an irrigation management
 cw_output <- CW_run_simulation(X, cw_input, FUN_IRRIG = fun_irrig_half_RAW)
 plot(cw_output)
 
 # Total amount of irrigation applied (mm)
-sum(cw_output$Ir)
+cw_output |> group_by(lubridate::year(DatesR)) |> summarise(irrig_volume = sum(Ir))
 ```
 
diff --git a/README.md b/README.md
index 963042f80391391a069d7ab914eda05920231886..6c63728acec783a3b967b031be297d281b28f992 100644
--- a/README.md
+++ b/README.md
@@ -1,75 +1,91 @@
-
-<!-- README.md is generated from README.Rmd. Please edit that file -->
-
-# CropWat
-
-<!-- badges: start -->
-<!-- badges: end -->
-
-CropWat is an R Implementation of the FAO CropWat Model.
-
-This implements the functions describing water balance on an irrigated
-crop as described in FAO publications of the Irrigation and Drainage
-Series, namely, No. 56 “Crop Evapotranspiration - Guidelines for
-computing crop water requirements” and No. 33 titled “Yield response to
-water”.
-
-## Installation
-
-You can install the development version of CropWat like so:
-
-``` r
-# install.packages("remotes")
-remotes::install_git("https://forgemia.inra.fr/umr-g-eau/cropwat.git")
-```
-
-## Example
-
-This is a basic example which shows you how to simulate water balance of
-an irrigated crop.
-
-``` r
-# Load library
-library(CropWat)
-
-# Import example climate dataset
-data(ZH_3_clim)
-
-# Selecting year 2010
-meteo <- ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") &
-                   ZH_3_clim$Date <= as.Date("2010-12-31"), ]
-
-# Formatting model input
-cw_input <- CW_create_input("SB2023-soja",
-                            DatesR = meteo$Date,
-                            ETo = meteo$ETP,
-                            P = meteo$Ptot,
-                            soil_depth = 1.2,
-                            AWC = 140)
-plot(cw_input)
-```
-
-<img src="man/figures/README-example-1.png" width="100%" />
-
-``` r
-
-# Initial state of the model set up
-X <- CW_create_state(cw_input = cw_input)
-
-# Choose an irrigation management
-# Example: Fill Soil moisture depletion when half of RAW is reached
-fun_irrig_half_RAW <- CW_irrig_fun_factory(RAW_ratio = 0.5, apply_Dr = TRUE)
-
-# Simulate water balance with an irrigation management
-cw_output <- CW_run_simulation(X, cw_input, FUN_IRRIG = fun_irrig_half_RAW)
-plot(cw_output)
-```
-
-<img src="man/figures/README-example-2.png" width="100%" />
-
-``` r
-
-# Total amount of irrigation applied (mm)
-sum(cw_output$Ir)
-#> [1] 375.3663
-```
+
+<!-- README.md is generated from README.Rmd. Please edit that file -->
+
+# CropWat
+
+<!-- badges: start -->
+<!-- badges: end -->
+
+CropWat is an R Implementation of the FAO CropWat Model.
+
+This implements the functions describing water balance on an irrigated
+crop as described in FAO publications of the Irrigation and Drainage
+Series, namely, No. 56 “Crop Evapotranspiration - Guidelines for
+computing crop water requirements” and No. 33 titled “Yield response to
+water”.
+
+## Installation
+
+You can install the development version of CropWat like so:
+
+``` r
+# install.packages("remotes")
+remotes::install_git("https://forgemia.inra.fr/umr-g-eau/cropwat.git")
+```
+
+## Example
+
+This is a basic example which shows you how to simulate water balance of
+an irrigated crop.
+
+``` r
+# Load library
+library(CropWat)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+
+# Import example climate dataset
+data(ZH_3_clim)
+
+# Selecting year 2010
+meteo <- ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") &
+                   ZH_3_clim$Date <= as.Date("2014-12-31"), ]
+
+# Formatting model input
+cw_input <- CW_create_input("SB2023-soja",
+                            DatesR = meteo$Date,
+                            ETo = meteo$ETP,
+                            P = meteo$Ptot,
+                            soil_depth = 1.2,
+                            AWC = 140)
+plot(cw_input)
+```
+
+<img src="man/figures/README-example-1.png" width="100%" />
+
+``` r
+
+# Initial state of the model set up
+X <- CW_create_state(cw_input = cw_input)
+
+# Choose an irrigation management
+# Example: Fill Soil moisture depletion when half of RAW is reached
+fun_irrig_half_RAW <- CW_irrig_fun_factory(RAW_ratio = 1.25, apply_Dr = TRUE)
+
+# Simulate water balance with an irrigation management
+cw_output <- CW_run_simulation(X, cw_input, FUN_IRRIG = fun_irrig_half_RAW)
+plot(cw_output)
+```
+
+<img src="man/figures/README-example-2.png" width="100%" />
+
+``` r
+
+# Total amount of irrigation applied (mm)
+cw_output |> group_by(lubridate::year(DatesR)) |> summarise(irrig_volume = sum(Ir))
+#> # A tibble: 5 × 2
+#>   `lubridate::year(DatesR)` irrig_volume
+#>                       <dbl>        <dbl>
+#> 1                      2010         212.
+#> 2                      2011         191.
+#> 3                      2012         287.
+#> 4                      2013         213.
+#> 5                      2014         139.
+```
diff --git a/man/CW_create_input.Rd b/man/CW_create_input.Rd
index 9e8fc840a84c31f3823e1a3a2a579fefb7dfd689..7fc559e27846bef0324be705318a5561a489e699 100644
--- a/man/CW_create_input.Rd
+++ b/man/CW_create_input.Rd
@@ -6,9 +6,7 @@
 \usage{
 CW_create_input(
   crop,
-  year,
-  DatesR = seq(as.Date(paste0(year, "-01-01")), as.Date(paste0(year, "-12-31")), by =
-    "1 day"),
+  DatesR,
   ETo,
   P,
   soil_depth,
@@ -20,9 +18,6 @@ CW_create_input(
 \arguments{
 \item{crop}{The code of the crop}
 
-\item{year}{Year of simulation (Only used for detecting leap year).
-If \code{NULL}, the calculation is limited to the crop cycle of the plant}
-
 \item{DatesR}{Simulation period (\link{vector} of \link{Date})}
 
 \item{ETo}{Potential Evaporation (mm/day)}
@@ -43,13 +38,18 @@ A \link{tibble} containing the input times series.
 \description{
 Create CropWat model input
 }
+\details{
+The crop cycle begins at the first matching sowing date in the simulation
+period. So, first time steps of simulation if are not in a crop cycle even
+if they occur during the crop cycle.
+}
 \examples{
 # Import example climate dataset
 data(ZH_3_clim)
 str(ZH_3_clim)
-# Selecting year 2010
+# Selecting years 2010 and 2011
 meteo <-
-  ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") & ZH_3_clim$Date <= as.Date("2010-12-31"), ]
+  ZH_3_clim[ZH_3_clim$Date >= as.Date("2010-01-01") & ZH_3_clim$Date <= as.Date("2011-12-31"), ]
 # Create model input
 cw_input <- CW_create_input("SB2023-soja",
                             DatesR = meteo$Date,
diff --git a/man/calc_Kc.Rd b/man/calc_Kc.Rd
deleted file mode 100644
index 712604f9d78a9b09ee85505d583aff8aa93abbdb..0000000000000000000000000000000000000000
--- a/man/calc_Kc.Rd
+++ /dev/null
@@ -1,30 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/calc_Kc.R
-\name{calc_Kc}
-\alias{calc_Kc}
-\title{Compute crop coefficient time series for one crop cycle or calendar year}
-\usage{
-calc_Kc(cp, year, sowing_date = cp$sowing_date)
-}
-\arguments{
-\item{cp}{Crop parameters (See \link{get_crop_params})}
-
-\item{year}{Year of simulation (Only used for detecting leap year).
-If \code{NULL}, the calculation is limited to the crop cycle of the plant}
-
-\item{sowing_date}{Sowing date in format "MM-DD"}
-}
-\value{
-A \link{vector} of Kc for each day of the year or the crop cycle.
-}
-\description{
-Compute crop coefficient time series for one crop cycle or calendar year
-}
-\examples{
-Kc <- calc_Kc(get_crop_params("SB2023-soja"), year = NULL)
-plot(Kc, type = "l")
-
-Kc <- calc_Kc(get_crop_params("SB2023-soja"), year = 2024)
-plot(Kc, type = "l")
-
-}
diff --git a/man/calc_RAW.Rd b/man/calc_RAW.Rd
deleted file mode 100644
index 4759abf84499a8bf1b323f83789c9f99db0ba0f3..0000000000000000000000000000000000000000
--- a/man/calc_RAW.Rd
+++ /dev/null
@@ -1,29 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/calc_RAW.R
-\name{calc_RAW}
-\alias{calc_RAW}
-\title{Calculation of Readily Available Water (RAW)}
-\usage{
-calc_RAW(TAW, p)
-}
-\arguments{
-\item{TAW}{Total Available Water (mm). See \link{calc_TAW}}
-
-\item{p}{fraction of Readily Available Water time series. See \link{calc_p}}
-}
-\value{
-A \link{vector} of Readily Available Water.
-}
-\description{
-Calculation of Readily Available Water (RAW)
-}
-\examples{
-cp <- get_crop_params("SB2023-soja")
-TAW <- calc_TAW(cp,
-                AWC = 140,
-                soil_depth = 1.2,
-                year = 2024)
-p <- calc_p(cp, year = 2024)
-RAW <- calc_RAW(TAW, p)
-plot(RAW, type = "l")
-}
diff --git a/man/calc_TAW.Rd b/man/calc_TAW.Rd
deleted file mode 100644
index 2fef09401bd4865a7861e59bfaf2b4ec2e0d40e4..0000000000000000000000000000000000000000
--- a/man/calc_TAW.Rd
+++ /dev/null
@@ -1,47 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/calc_TAW.R
-\name{calc_TAW}
-\alias{calc_TAW}
-\title{Calculation of Total Available Water (TAW)}
-\usage{
-calc_TAW(
-  cp,
-  AWC,
-  soil_depth,
-  year,
-  sowing_date = cp$sowing_date,
-  root_depth = calc_root_depth(cp, soil_depth, year, sowing_date)
-)
-}
-\arguments{
-\item{cp}{Crop parameters (See \link{get_crop_params})}
-
-\item{AWC}{Available Water Capacity (mm)}
-
-\item{soil_depth}{Soil depth (m)}
-
-\item{year}{Year of simulation (Only used for detecting leap year).
-If \code{NULL}, the calculation is limited to the crop cycle of the plant}
-
-\item{sowing_date}{Sowing date in format "MM-DD"}
-
-\item{root_depth}{Root depth time series (m). See \link{calc_root_depth}.}
-}
-\value{
-A \link{vector} of Total Available Water (mm) for each day of the year or the crop cycle.
-}
-\description{
-Calculation of Total Available Water (TAW)
-}
-\details{
-Parameters \code{cp}, \code{year}, and \code{sowing_date} are useless if \code{root_depth} is
-provided.
-}
-\examples{
-TAW <- calc_TAW(get_crop_params("SB2023-soja"),
-                AWC = 140,
-                soil_depth = 1.2,
-                year = 2024)
-plot(TAW, type = "l")
-
-}
diff --git a/man/calc_isCycle.Rd b/man/calc_isCycle.Rd
index 53f5642772d812061e618193a38bec38be9653d3..d7b0dafc66751af37fe417978708a3c9afcad290 100644
--- a/man/calc_isCycle.Rd
+++ b/man/calc_isCycle.Rd
@@ -4,12 +4,12 @@
 \alias{calc_isCycle}
 \title{Compute cycle period extend during the year}
 \usage{
-calc_isCycle(cp, year, sowing_date = cp$sowing_date)
+calc_isCycle(cp, DatesR, sowing_date = cp$sowing_date)
 }
 \arguments{
 \item{cp}{Crop parameters (See \link{get_crop_params})}
 
-\item{year}{Year of simulation (Only used for detecting leap year).
+\item{DatesR}{A \link{vector} of continuous \link{Date}
 If \code{NULL}, the calculation is limited to the crop cycle of the plant}
 
 \item{sowing_date}{Sowing date in format "MM-DD"}
@@ -21,6 +21,8 @@ A \link{vector} of \link{logical} of the crop cycle for each day of the year.
 Compute cycle period extend during the year
 }
 \examples{
-isCycle <- calc_isCycle(get_crop_params("SB2023-soja"), year = 2024)
+DatesR <- seq(as.Date("2010-03-01"), as.Date("2010-10-31"), by = "1 day")
+isCycle <- calc_isCycle(get_crop_params("SB2023-soja"), DatesR)
+plot(isCycle)
 
 }
diff --git a/man/calc_p.Rd b/man/calc_p.Rd
deleted file mode 100644
index 9438c02f00e807b3852af399b1e5e45e2280abd8..0000000000000000000000000000000000000000
--- a/man/calc_p.Rd
+++ /dev/null
@@ -1,28 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/calc_p.R
-\name{calc_p}
-\alias{calc_p}
-\title{Compute critical depletion fraction (p) time series for one crop cycle or calendar year}
-\usage{
-calc_p(cp, year, sowing_date = cp$sowing_date)
-}
-\arguments{
-\item{cp}{Crop parameters (See \link{get_crop_params})}
-
-\item{year}{Year of simulation (Only used for detecting leap year).
-If \code{NULL}, the calculation is limited to the crop cycle of the plant}
-
-\item{sowing_date}{Sowing date in format "MM-DD"}
-}
-\value{
-A \link{vector} of critical depletion fraction for each day of the year or the crop cycle.
-}
-\description{
-\emph{p} is the fraction RAW / TAW
-}
-\examples{
-p <- calc_p(get_crop_params("SB2023-soja"),
-                      year = 2024)
-plot(p, type = "l")
-
-}
diff --git a/man/calc_params.Rd b/man/calc_params.Rd
new file mode 100644
index 0000000000000000000000000000000000000000..ab605bd749c33d1742bed5a4fbd1f86f17e6f394
--- /dev/null
+++ b/man/calc_params.Rd
@@ -0,0 +1,81 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/calc_Kc.R, R/calc_RAW.R, R/calc_TAW.R,
+%   R/calc_p.R, R/calc_root_depth.R
+\name{calc_Kc}
+\alias{calc_Kc}
+\alias{calc_RAW}
+\alias{calc_TAW}
+\alias{calc_p}
+\alias{calc_root_depth}
+\title{Compute crop parameters time series from crop parameters pivot points}
+\usage{
+calc_Kc(cp, DatesR = NULL, sowing_date = cp$sowing_date)
+
+calc_RAW(TAW, p)
+
+calc_TAW(
+  cp,
+  AWC,
+  soil_depth,
+  DatesR = NULL,
+  sowing_date = cp$sowing_date,
+  root_depth = calc_root_depth(cp, soil_depth, DatesR, sowing_date)
+)
+
+calc_p(cp, DatesR = NULL, sowing_date = cp$sowing_date)
+
+calc_root_depth(cp, soil_depth, DatesR = NULL, sowing_date = cp$sowing_date)
+}
+\arguments{
+\item{cp}{Crop parameters (See \link{get_crop_params})}
+
+\item{DatesR}{A \link{vector} of continuous \link{Date}
+If \code{NULL}, the calculation is limited to the crop cycle of the plant}
+
+\item{sowing_date}{Sowing date in format "MM-DD"}
+
+\item{TAW}{Total Available Water (mm). See \link{calc_TAW}}
+
+\item{p}{fraction of Readily Available Water time series. See \link{calc_p}}
+
+\item{AWC}{Available Water Capacity (mm)}
+
+\item{soil_depth}{Soil depth (m)}
+
+\item{root_depth}{Root depth time series (m). See \link{calc_root_depth}}
+}
+\value{
+A \link{vector} of the parameter for each day of the crop cycle or the period defined by \code{DatesR}.
+}
+\description{
+These functions compute the following parameters:
+}
+\details{
+\itemize{
+\item \code{Calc_Kc}: crop coefficient $K_c$
+\item \code{calc_p}: critical depletion fraction $p=RAW/TAW$
+\item \code{calc_root_depth}: root depth in m
+\item \code{calc_RAW}: Readily Available Water (RAW) in mm
+\item \code{calc_TAW}:  Total Available Water (TAW) in mm
+}
+
+For \code{calc_TAW}, parameters \code{cp}, \code{year}, and \code{sowing_date} are useless if \code{root_depth} is
+provided.
+}
+\examples{
+# Compute Kc for the crop cycle
+Kc <- calc_Kc(get_crop_params("SB2023-soja"))
+plot(Kc, type = "l")
+
+# Compute Kc for a given period (less than one year)
+# with default sowing date defined in crop parameters
+DatesR <- seq(as.Date("2010-03-01"), as.Date("2010-10-31"), by = "1 day")
+Kc <- calc_Kc(get_crop_params("SB2023-soja"), DatesR = DatesR)
+plot(Kc, type = "l")
+
+# Compute Kc for a given period with user defined sowing date
+Kc <- calc_Kc(get_crop_params("FAO-MAIZE"),
+              DatesR = DatesR,
+              sowing_date = "05-01")
+plot(Kc, type = "l")
+}
diff --git a/man/calc_root_depth.Rd b/man/calc_root_depth.Rd
deleted file mode 100644
index 305afe7c6554529a2785cd2557d6e7a5f29128cf..0000000000000000000000000000000000000000
--- a/man/calc_root_depth.Rd
+++ /dev/null
@@ -1,31 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/calc_root_depth.R
-\name{calc_root_depth}
-\alias{calc_root_depth}
-\title{Compute root depth time series for one crop cycle or calendar year}
-\usage{
-calc_root_depth(cp, soil_depth, year, sowing_date = cp$sowing_date)
-}
-\arguments{
-\item{cp}{Crop parameters (See \link{get_crop_params})}
-
-\item{soil_depth}{Soil depth (m)}
-
-\item{year}{Year of simulation (Only used for detecting leap year).
-If \code{NULL}, the calculation is limited to the crop cycle of the plant}
-
-\item{sowing_date}{Sowing date in format "MM-DD"}
-}
-\value{
-A \link{vector} of root depth (m) for each day of the year or the crop cycle.
-}
-\description{
-Compute root depth time series for one crop cycle or calendar year
-}
-\examples{
-Zr <- calc_root_depth(get_crop_params("SB2023-soja"),
-                      soil_depth = 1.2,
-                      year = 2024)
-plot(Zr, type = "l")
-
-}
diff --git a/man/figures/README-example-1.png b/man/figures/README-example-1.png
index c6bb85000f3bbf6c9358008cd15ccca8ebc9f82e..d62834a14498b9cdd3eb6d90a38d1534e19ac27f 100644
Binary files a/man/figures/README-example-1.png and b/man/figures/README-example-1.png differ
diff --git a/man/figures/README-example-2.png b/man/figures/README-example-2.png
index 606f7e098a670e0967f2f68d1f06767df333a118..5b4f760f3d13b51e0c1ed62638d01263517166ba 100644
Binary files a/man/figures/README-example-2.png and b/man/figures/README-example-2.png differ
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000000000000000000000000000000000000..80d06924094400190a08075c0107dbce018b4c5e
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,12 @@
+# This file is part of the standard setup for testthat.
+# It is recommended that you do not modify it.
+#
+# Where should you do additional test configuration?
+# Learn more about the roles of various files in:
+# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
+# * https://testthat.r-lib.org/articles/special-files.html
+
+library(testthat)
+library(CropWat)
+
+test_check("CropWat")
diff --git a/tests/testthat/test-calc_interpolated_param.R b/tests/testthat/test-calc_interpolated_param.R
new file mode 100644
index 0000000000000000000000000000000000000000..6cca315f600827ce25d3775853da0f2d249616ab
--- /dev/null
+++ b/tests/testthat/test-calc_interpolated_param.R
@@ -0,0 +1,44 @@
+test_that("calc_interpolated_param works", {
+  x <- c(2, 2, 1)
+  y <- c(1, 3, 2)
+  expect_equal(calc_interpolated_param(NULL, NA, x, y, 1, 1),
+               c(1, 1, 2, 3, 2))
+  DatesR <- seq(as.Date("2000-01-01"), as.Date("2000-01-07"), by = "1 day")
+  expect_error(calc_interpolated_param(DatesR, NA, x, y, 1, 1))
+  expect_error(calc_interpolated_param(DatesR, "1-223", x, y, 1, 1))
+  expect_error(calc_interpolated_param(DatesR, "04/04", x, y, 1, 1))
+  expect_error(calc_interpolated_param(seq(as.Date("2000-01-01"), as.Date("2001-01-02"), by = "1 day"), "04-04", x, y, 1, 1))
+  expect_equal(calc_interpolated_param(DatesR, "01-02", x, y, 1, 1),
+               c(1,1,1,2,3,2,1))
+})
+test_that("calc_interpolated_param works over new year's day :)", {
+  cp <- get_crop_params("SB2023-soja")
+  sowing_date = "11-01"
+  x <- c(cp$Lini, cp$Ldev, cp$Lmid, cp$Lend)
+  y <- c(cp$Kini, cp$Kmax, cp$Kmax, cp$Kend)
+  yleft <- cp$Kini
+  yright <- cp$Kini
+  DatesR <-  seq(as.Date("2000-10-01"), as.Date("2001-09-30"), by = "1 day")
+  p <- calc_interpolated_param(
+    DatesR,
+    sowing_date = sowing_date,
+    x = x,
+    y = y,
+    yleft = yleft,
+    yright = yright
+  )
+  expect_equal(p[cp$Lini + 31], cp$Kini) # 10-31
+  expect_gt(p[cp$Lini + 32], cp$Kini) # 11-01 = sowing date
+  expect_lt(p[cp$Lini + cp$Ldev + 30], cp$Kmax) # Day before end of dev
+  expect_equal(p[cp$Lini + cp$Ldev + 31], cp$Kmax) # Max plateau
+  DatesR <-  seq(as.Date("2001-01-01"), as.Date("2001-10-31"), by = "1 day")
+  p <- calc_interpolated_param(
+    DatesR,
+    sowing_date = sowing_date,
+    x = x,
+    y = y,
+    yleft = yleft,
+    yright = yright
+  )
+  expect_true(all(p == cp$Kini))
+})
diff --git a/tests/testthat/test-get_yearly_cycles.R b/tests/testthat/test-get_yearly_cycles.R
new file mode 100644
index 0000000000000000000000000000000000000000..2947a9f1337556b0cf6327e19e61ffc94d59e62b
--- /dev/null
+++ b/tests/testthat/test-get_yearly_cycles.R
@@ -0,0 +1,46 @@
+test_that("get_yearly_cycles works", {
+  # Regular calendar year
+  DatesR <- seq(as.Date("2019-01-01"), as.Date("2019-12-31"), by = "1 day")
+  expect_equal(get_yearly_cycles(DatesR), list("2019" =
+                                                 list(
+                                                   year = 2019,
+                                                   start = DatesR[1],
+                                                   end = last(DatesR),
+                                                   dates = DatesR,
+                                                   which = seq(365)
+                                                 )))
+  # Calendar leap year
+  DatesR <- seq(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "1 day")
+  expect_equal(get_yearly_cycles(DatesR), list("2020" =
+                                                 list(
+                                                   year = 2020,
+                                                   start = DatesR[1],
+                                                   end = last(DatesR),
+                                                   dates = DatesR,
+                                                   which = seq(366)
+                                                 )))
+  # Not calendar year
+  DatesR <- seq(as.Date("2020-06-01"), as.Date("2021-05-31"), by = "1 day")
+  expect_equal(get_yearly_cycles(DatesR), list("2020" =
+                                                 list(
+                                                   year = 2020,
+                                                   start = DatesR[1],
+                                                   end = last(DatesR),
+                                                   dates = DatesR,
+                                                   which = seq(365)
+                                                 )))
+  # Not complete year into calendar year
+  DatesR <- seq(as.Date("2020-06-01"), as.Date("2020-12-31"), by = "1 day")
+  expect_equal(get_yearly_cycles(DatesR), list("2020" =
+                                                 list(
+                                                   year = 2020,
+                                                   start = DatesR[1],
+                                                   end = last(DatesR),
+                                                   dates = DatesR,
+                                                   which = seq(length(DatesR))
+                                                 )))
+  # 2 years
+  DatesR <- seq(as.Date("2019-01-01"), as.Date("2020-12-31"), by = "1 day")
+  cycles <- get_yearly_cycles(DatesR)
+
+})