---
title: "Severn_06: Modeling a regulated diversion"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Severn_06: Modeling a regulated diversion}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.asp = 0.68,
  out.width = "70%",
  fig.align = "center"
)
```

```{r setup}
library(airGRiwrm)
data(Severn)
```

## The study case

In this vignette, we are still using the study case of the vignette #1 and #2, and
we are going to simulate a diversion at the node "54001" to provide flow to the node
"54029" in order to support low flows in the Severn river.

This objective is to maintain a minimum flow equals to the 3th decile of the flow
at station "54029" without remaining less than the first decile of the flow downstream
the station "54001".

Let's compute the flow quantiles at each station in m3/s:

```{r}
Qobs <- cbind(sapply(Severn$BasinsObs, function(x) {x$discharge_spec}))
Qobs <- Qobs[, Severn$BasinsInfo$gauge_id]
Qobs_m3s <- t(apply(Qobs, 1, function(r) r * Severn$BasinsInfo$area * 1E3 / 86400))
apply(Qobs_m3s[, c("54029", "54001")], 2, quantile, probs = seq(0,1,0.1), na.rm = TRUE)
```

The rule to apply is expressed as follow:

> The diversion from "54001" is computed to maintain a minimum flow of 5.3 m3/s at
the gauging station "54029". The diversion is allowed as far as the flow at the
gauging station "54001" is above 11.5 m3/s.

## Network

```{r}

nodes_div <- Severn$BasinsInfo[, c("gauge_id", "downstream_id", "distance_downstream", "area")]
nodes_div$model <- "RunModel_GR4J"
nodes_div <- rbind(nodes_div, data.frame(gauge_id = "54001",
                                         downstream_id = "54029",
                                         distance_downstream = 25,
                                         model = "Diversion",
                                         area = NA))
renameCols <- list(id = "gauge_id", down = "downstream_id", length = "distance_downstream")
griwrmV06 <- CreateGRiwrm(nodes_div, renameCols)
plot(griwrmV06)
```

## GRiwrmInputsModel object

We produce below the same operations as in the vignette "V02_Calibration_SD_model" to prepare the input data:

```{r}
data(Severn)
nodes <- Severn$BasinsInfo[, c("gauge_id", "downstream_id", "distance_downstream", "area")]
nodes$model <- "RunModel_GR4J"
griwrm <- CreateGRiwrm(nodes, list(id = "gauge_id", down = "downstream_id", length = "distance_downstream"))
BasinsObs <- Severn$BasinsObs
DatesR <- BasinsObs[[1]]$DatesR
PrecipTot <- cbind(sapply(BasinsObs, function(x) {x$precipitation}))
PotEvapTot <- cbind(sapply(BasinsObs, function(x) {x$peti}))
Precip <- ConvertMeteoSD(griwrm, PrecipTot)
PotEvap <- ConvertMeteoSD(griwrm, PotEvapTot)
```

The main difference here is that we need to provide a diverted flow and a minimum
remaining flow at station "54029". As, the diverted flow will be calculated during
simulation, we provide a initial diverted flow equals to zero for all the time steps.

```{r}
Qdiv <- matrix(rep(0, length(DatesR)), ncol = 1)
colnames(Qdiv) <- "54001"
Qmin <- matrix(rep(11.5 * 86400, length(DatesR)), ncol = 1)
colnames(Qmin) <- "54001"
IM_div <- CreateInputsModel(griwrmV06, DatesR, Precip, PotEvap, Qinf = Qdiv, Qmin = Qmin)
```

## Implementation of the regulation controller

### The supervisor

The simulation is piloted through a `Supervisor` that can contain one or more
`Controller`. The supervision time step will be here the same as the simulation
time step:  1 day. Each day, the decision is taken for the current day from the
measurement simulated the previous time step.

```{r}
sv <- CreateSupervisor(IM_div, TimeStep = 1L)
```

### The control logic function

On a Diversion node, the minimum remaining flow is provided with the inputs and
is automatically taken into account by the model. So the control logic function
has only to take care about how much water to divert to the gauging station
"54002".

We need to enclose the logic function in a function factory providing the
Supervisor in the environment of the function:

```{r}
#' @param sv the Supervisor environment
logicFunFactory <- function(sv) {
  #' @param Y Flow measured at "54002" the previous time step
  function(Y) {
    Qnat <- Y
    #  We need to remove the diverted flow to compute the natural flow at "54002"
    lastU <- sv$controllers[[sv$controller.id]]$U
    if (length(lastU) > 0) {
      Qnat <- max(0, Y + lastU)
    }
    return(-max(5.3 * 86400 - Qnat, 0))
  }
}
```

### The controller

We declare the controller which defines where is the measurement `Y` , where to
apply the decision `U` with which logic function:

```{r}
CreateController(sv,
                 ctrl.id = "Low flow support",
                 Y = "54029",
                 U = "54001",
                 FUN = logicFunFactory(sv))
```


## Running the simulation

First we need to create a `GRiwrmRunOptions` object and load the parameters calibrated in the vignette "V02_Calibration_SD_model":

```{r}
# Running simulation on year 2003
IndPeriod_Run <- which(
  DatesR >= as.POSIXct("2003-03-01", tz = "UTC") &
    DatesR <= as.POSIXct("2004-01-01", tz = "UTC")
)
IndPeriod_WarmUp = seq(IndPeriod_Run[1] - 366,IndPeriod_Run[1] - 1)
RunOptions <- CreateRunOptions(IM_div,
                               IndPeriod_WarmUp = IndPeriod_WarmUp,
                               IndPeriod_Run = IndPeriod_Run)
ParamV02 <- readRDS(system.file("vignettes", "ParamV02.RDS", package = "airGRiwrm"))
```

The node "54029" was initially an upstream node. As it receives water from "54001"
it is no longer an upstream node and needs a parameter for routing its upstream
flows. We arbitrary say that the velocity in the channel between "54001" and
"54029" is 1 m/s.

```{r}
ParamV02$`54029` <- c(1, ParamV02$`54029`)
```

And we run the supervised model:

```{r}
OM_div <- RunModel(sv, RunOptions = RunOptions, Param = ParamV02)
```

To compare results with diversion and without diversion, we run the model without
the supervision (remember that we have set the diverted flow at zero in the inputs):

```{r}
OM_nat <- RunModel(IM_div, RunOptions = RunOptions, Param = ParamV02)
```


## Exploring results

Let's plot the diverted flow, and compare the flow at stations 54029 and 54001,
with and without low-flow support at station 54001:

```{r, fig.asp=1}
dfQdiv <- data.frame(DatesR = OM_div[[1]]$DatesR,
                     Diverted_flow = OM_div$`54001`$Qdiv_m3 / 86400)

oldpar <- par(mfrow=c(3,1), mar = c(2.5,4,1,1))
plot.Qm3s(dfQdiv)

# Plot natural and influenced flow at station "54001" and "54029"
thresholds <- c("54001" = 11.5, "54029" = 5.3)
lapply(names(thresholds), function(id) {
  df <- cbind(attr(OM_div, "Qm3s")[, c("DatesR", id)],
                   attr(OM_nat, "Qm3s")[, id])
  names(df) <- c("DatesR",
                      paste(id, "with low-flow support"),
                      paste(id, "natural flow"))
  plot.Qm3s(df, ylim = c(0,50), lty = c("solid", "dashed"))
  abline(h = thresholds[id], col = "green", lty = "dotted")
})
par(oldpar)
```

