RunModel.InputsModel.R 5.68 KiB
#' Wrapper for [airGR::RunModel] for one sub-basin
#'
#' @inheritParams airGR::RunModel
#' @param x \[object of class \emph{InputsModel}\] see [airGR::CreateInputsModel] for details
#' @param ... Further arguments for compatibility with S3 methods
#'
#' @returns \[object of class \emph{OutputsModel}\] returned by [airGR::RunModel]
#' (See Value section of [airGR::RunModel_GR4J]) completed by new items:
#' - `Qsim_m3`: simulated flow in cubic meters per time step
#' - `Qover_m3` volumes of over abstractions which occurs when `RunModel_Lag` warns
#' for negative simulated flows
#' - `Qnat`: only present in case of Diversion in the node, simulated flow in mm
#' per time step before application of the Diversion
#' - `Qdiv_m3`: only present in case of Diversion in the node, simulated diverted flow in
#' cubic meters per time step. The latter differs from the flows time series provided
#' in argument `Qinf` of [CreateInputsModel.GRiwrm] by the limitation of diversion
#' applied by the minimum flow threshold `Qmin` to keep flowing in the river
#' @export
RunModel.InputsModel <- function(x = NULL,
                                 RunOptions,
                                 Param,
                                 FUN_MOD = NULL,
                                 InputsModel = NULL,
                                 ...) {
  if (is.null(x)) {
    if (!is.null(InputsModel)) {
      x <- InputsModel
    } else {
      stop("`x` or `InputsModel` must be defined")
  } else {
    if (!is.null(InputsModel)) {
      stop("`x` and `InputsModel` can't be defined at the same time")
  if (is.null(FUN_MOD)) {
    if (x$isReservoir) {
      FUN_MOD <- "RunModel_Reservoir"
    } else {
      FUN_MOD <- x$FUN_MOD
  # Avoiding Error in `FUN_MOD(x, RunOptions, Param)`: NA/NaN/Inf in foreign function call (arg 7)
  RunOptions$IniStates[is.na(RunOptions$IniStates)] <- 0
  FUN_MOD <- match.fun(FUN_MOD)
  if (identical(FUN_MOD, RunModel_Lag)) {
    OutputsModel <- RunModel_Routing(x, RunOptions, Param)
  } else if ((inherits(x, "GR") & is.null(x$UpstreamNodes)) | identical(FUN_MOD, RunModel_Reservoir)) {
    # Upstream basins and Reservoir are launch directly
    OutputsModel <- FUN_MOD(x, RunOptions, Param)
  } else {
    # Intermediate basins (other than reservoir) are launched with SD capabilities
    if (!is.null(x$UpstreamNodes) & !inherits(x, "SD")) {
      # For calibration of node with diversion
      class(x) <- c(class(x), "SD")
    OutputsModel <- airGR::RunModel(x, RunOptions, Param, FUN_MOD)
    OutputsModel <- calcOverAbstraction(OutputsModel, FALSE)
    OutputsModel$RunOptions <- calcOverAbstraction(OutputsModel$RunOptions, TRUE)
  OutputsModel$RunOptions$TimeStep <- RunOptions$FeatFUN_MOD$TimeStep
  if (is.null(OutputsModel$Qsim_m3)) {
    # Add Qsim_m3 in m3/timestep
    OutputsModel$Qsim_m3 <-
      OutputsModel$Qsim * sum(x$BasinAreas, na.rm = TRUE) * 1e3
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
if ("WarmUpQsim" %in% RunOptions$Outputs_Sim && is.null(OutputsModel$RunOptions$WarmUpQsim_m3)) { OutputsModel$RunOptions$WarmUpQsim_m3 <- OutputsModel$RunOptions$WarmUpQsim * sum(x$BasinAreas, na.rm = TRUE) * 1e3 } if (x$hasDiversion && !x$isReservoir) { OutputsModel <- RunModel_Diversion(x, RunOptions, OutputsModel) } return(OutputsModel) } #' Model the diversion of a flow from an existing modeled node #' #' On a Diversion node, this function is called after `airGR::RunModel` to #' divert a part of the flow to another node than the original downstream one. #' #' @param InputsModel \[object of class \emph{InputsModel}\] see #' [airGR::CreateInputsModel] for details #' @param RunOptions Same parameter as in [RunModel.GRiwrmInputsModel] #' @param OutputsModel Output of [airGR::RunModel] #' @param updateQsim [logical] for updating Qsim after diversion in the output #' #' @return Updated `OutputsModel` object after diversion #' @noRd #' RunModel_Diversion <- function(InputsModel, RunOptions, OutputsModel, updateQsim = TRUE) { OutputsModel$Qnat <- OutputsModel$Qsim lQ <- calc_Qdiv(OutputsModel$Qsim_m3, InputsModel$Qdiv[RunOptions$IndPeriod_Run], InputsModel$Qmin[RunOptions$IndPeriod_Run]) #message(paste(InputsModel$Qdiv[RunOptions$IndPeriod_Run], lQ$Qdiv, lQ$Qsim, InputsModel$Qmin[RunOptions$IndPeriod_Run], sep = ", ")) OutputsModel$Qdiv_m3 <- lQ$Qdiv OutputsModel$Qsim_m3 <- lQ$Qsim if (updateQsim) { OutputsModel$Qsim <- OutputsModel$Qsim_m3 / sum(InputsModel$BasinAreas, na.rm = TRUE) / 1e3 } if ("WarmUpQsim" %in% RunOptions$Outputs_Sim) { lQ <- calc_Qdiv(OutputsModel$RunOptions$WarmUpQsim_m3, InputsModel$Qdiv[RunOptions$IndPeriod_WarmUp], InputsModel$Qmin[RunOptions$IndPeriod_WarmUp]) OutputsModel$RunOptions$WarmUpQdiv_m3 <- lQ$Qdiv OutputsModel$RunOptions$WarmUpQsim_m3 <- lQ$Qsim } return(OutputsModel) } #' Compute diverted and simulated flow at a diversion #' #' @param Qnat [numeric] time series of flow before diversion (m3/time step) #' @param Qdiv [numeric] time series of planned diverted flow (m3/time step) #' @param Qmin [numeric] time series of minimum flow after diversion (m3/time step) #' #' @return A [list] with items: #' - Qdiv, the diverted flow after limitation of minimum flow #' - Qsim, the simulated flow after diversion and limitation #' @noRd calc_Qdiv<- function(Qnat, Qdiv, Qmin) { Qsim <- Qnat - Qdiv indexQmin <- which(Qsim < Qmin & Qdiv > 0) if (any(indexQmin)) { #Qsim[indexQmin] <- sapply(indexQmin, function(i) min(Qnat[i], Qmin[i])) Qsim[indexQmin] <- pmin(Qnat[indexQmin], Qmin[indexQmin]) } return(list(Qsim = Qsim, Qdiv = Qnat - Qsim)) }
141