diff --git a/R/Calibration.GRiwrmInputsModel.R b/R/Calibration.GRiwrmInputsModel.R index e5e4265c45082c75eb4f3a2e300a24442f39f7f1..d460239ef243fca6a118dae140b5ebca4e91aad0 100644 --- a/R/Calibration.GRiwrmInputsModel.R +++ b/R/Calibration.GRiwrmInputsModel.R @@ -51,12 +51,12 @@ Calibration.GRiwrmInputsModel <- function(InputsModel, OutputsModel, useUpstreamQsim) IM <- l$InputsModel - message("Calibration.GRiwrmInputsModel: Processing sub-basins ", - paste(names(IM), collapse = ", "), " with ", id, " as gauged donor...") + message("Calibration.GRiwrmInputsModel: Processing sub-basins '", + paste(names(IM), collapse = "', '"), "' with '", id, "' as gauged donor...") IM$FUN_MOD <- "RunModel_Ungauged" attr(RunOptions[[id]], "GRiwrmRunOptions") <- l$RunOptions } else { - message("Calibration.GRiwrmInputsModel: Processing sub-basin ", id, "...") + message("Calibration.GRiwrmInputsModel: Processing sub-basin '", id, "'...") if (useUpstreamQsim && any(IM$UpstreamIsModeled)) { # Update InputsModel$Qupstream with simulated upstream flows IM <- UpdateQsimUpstream(IM, RunOptions[[id]], OutputsModel) diff --git a/R/CreateCalibOptions.GRiwrmInputsModel.R b/R/CreateCalibOptions.GRiwrmInputsModel.R index 19608e87333fdb3ac143154367274e8cfb65ce19..05453d4fca253681449e7f170d89e3c3023941bc 100644 --- a/R/CreateCalibOptions.GRiwrmInputsModel.R +++ b/R/CreateCalibOptions.GRiwrmInputsModel.R @@ -8,7 +8,7 @@ CreateCalibOptions.GRiwrmInputsModel <- function(x, FixedParam = NULL, ...) { } np <- getAllNodesProperties(attr(x, "GRiwrm")) np <- np[!np$DirectInjection, ] - gaugedIds <- np$id[np$calibration == "Gauged"] + gaugedIds <- np$id[np$gauged] if (!is.null(FixedParam)) { if (!(is.list(FixedParam) || is.numeric(FixedParam))) { @@ -50,7 +50,7 @@ CreateCalibOptions.GRiwrmInputsModel <- function(x, FixedParam = NULL, ...) { if (!is.null(FixedParam)) { FP <- FixedParam[[id]] } - if (np$calibration[np$id == id] == "Gauged") { + if (np$gauged[np$id == id]) { CalibOptions[[IM$id]] <- CreateCalibOptions( IM, FixedParam = FP, diff --git a/R/CreateGRiwrm.R b/R/CreateGRiwrm.R index fde53105a8a77dd7b9ee4490c7d1799ed3312caa..5ae83d686cb60e827e3dce46f34e0aab174839ce 100644 --- a/R/CreateGRiwrm.R +++ b/R/CreateGRiwrm.R @@ -105,6 +105,7 @@ CreateGRiwrm <- function(db, # Set automatic downstream donors for ungauged nodes griwrm$donor <- setDonor(griwrm) + checkUngaugedCluster(griwrm) griwrm <- sort(griwrm) @@ -291,7 +292,7 @@ setDonor <- function(griwrm) { } id <- griwrm$id[i] model <- griwrm$model[i] - if (is.na(model)) { + if (is.na(model) || model == "Diversion") { return(as.character(NA)) } if (model == "RunModel_Reservoir" && is.na(griwrm$down[i])){ @@ -340,3 +341,22 @@ refineReservoirDonor <- function(i, griwrm) { # No upstream ungauged nodes: Reservoir is its own donor! return(griwrm$id[i]) } + +checkUngaugedCluster <- function(griwrm) { + # Check presence of gauged nodes inside an ungauged cluster + clusters <- table(griwrm$donor) + clusters <- names(clusters[clusters > 1]) + lapply(clusters, function(gaugedId) { + g <- getUngaugedCluster(griwrm, gaugedId) + p <- getAllNodesProperties(griwrm) + upstreamIdsInCluster <- unique(g$id[!g$id %in% g$down]) + lapply(g$id, function(id) { + if (id != gaugedId) { + if (p$calibration[p$id == id] == "Gauged" && !id %in% upstreamIdsInCluster) { + stop("The gauged node '", id, "' is located in the cluster of the ungauged", + " nodes calibrated with the node '", gaugedId, "'") + } + } + }) + }) +} diff --git a/R/getNodeProperties.R b/R/getNodeProperties.R index a80e02262fa063945303d8e853e17fb151b889f0..02f8ce67ff8b864739242a462610d81698dae88d 100644 --- a/R/getNodeProperties.R +++ b/R/getNodeProperties.R @@ -16,7 +16,7 @@ #' - "Upstream" ([logical]): is the node an upstream node? #' - "RunOff" ([logical]): is the node contains an hydrological model? #' -#' `getAllNodeProperties` returns a [data.frame] constituted from the list returned +#' `getAllNodesProperties` returns a [data.frame] constituted from the list returned #' by `getNodeProperties` for all nodes. #' #' @details @@ -50,10 +50,23 @@ getNodeProperties <- function(id, griwrm) { Reservoir = !is.na(model) && model == "RunModel_Reservoir", airGR = grepl("RunModel_", donor_model) ) + p$gauged <- isNodeGauged(id, griwrm) if (p$DirectInjection) { p$calibration <- "NA" } else { - p$calibration <- ifelse(isNodeGauged(id, griwrm), "Gauged", "Ungauged") + if (p$gauged) { + if (p$Reservoir) { + p$calibration <- "Reservoir" + } else { + p$calibration <- "Gauged" + } + } else { + if (is.na(griwrm$donor[id]) || isNodeDownstream(griwrm, id, griwrm$donor[id])) { + p$calibration <- "Ungauged" + } else { + p$calibration <- "Receiver" + } + } } p$Upstream <- p$position == "Upstream" p$RunOff <- !p$DirectInjection && !p$Reservoir && donor_model != "RunModel_Lag" diff --git a/R/getNodeRanking.R b/R/getNodeRanking.R index 792c081cf807583e2faff49cb3b3b4718e60dd8a..113e20916406237cd51c64dd37ed7bb66c90288c 100644 --- a/R/getNodeRanking.R +++ b/R/getNodeRanking.R @@ -36,7 +36,8 @@ getNodeRanking <- function(griwrm) { upId <- upIds[1] #Browse the ungauged sub-network until the donor upDonor <- unique(g$donor[g$id == upId]) - g2 <- g[g$donor == upDonor, ] + cluster_nodes <- g$id[!is.na(g$donor) & g$donor == upDonor] + g2 <- g[g$id %in% cluster_nodes, ] # Check if upstream nodes have already been processed immediate_upstream_nodes <- g$id[!is.na(g$down) & g$down %in% g2$id] immediate_upstream_nodes <- immediate_upstream_nodes[!immediate_upstream_nodes %in% g2$id] diff --git a/R/plot.GRiwrm.R b/R/plot.GRiwrm.R index 8656c07995c2cb9b29610a2f7ec93ad96bbd94bc..ae3155de9a92d587f5d2ca092e16a40a6978171f 100644 --- a/R/plot.GRiwrm.R +++ b/R/plot.GRiwrm.R @@ -144,7 +144,8 @@ getNodeClass <- function(id, griwrm) { } else if (props$Reservoir) { nc <- "Reservoir" } else { - nc <- paste0(props$position, props$calibration) + nc <- paste0(props$position, + ifelse(props$gauged, "Gauged", "Ungauged")) } if (props$Diversion) nc <- paste0(nc, "Diversion") return(nc) diff --git a/R/utils.Calibration.R b/R/utils.Calibration.R index 24538a0fde18f8204bc5e68989152925a16a161c..e4bf639d779015418cd60953ab29f9ad604f6f34 100644 --- a/R/utils.Calibration.R +++ b/R/utils.Calibration.R @@ -56,7 +56,6 @@ reduceGRiwrmObj4Ungauged <- function(griwrm, obj) { return(obj) } - #' Set a reduced GRiwrm network for calibration of a sub-network with ungauged #' hydrological nodes #' @@ -78,26 +77,7 @@ updateParameters4Ungauged <- function(GaugedId, OutputsModel, useUpstreamQsim) { - ### Set the reduced network of the basin containing ungauged nodes ### - # Select nodes identified with the current node as donor gauged node - griwrm <- attr(InputsModel, "GRiwrm") - g2 <- griwrm[getDiversionRows(griwrm, TRUE), ] # Remove duplicated by Diversions - donorIds <- g2$id[!is.na(g2$donor) & g2$donor == GaugedId] - # Remove receiver nodes that haven't GaugedId as downstream node - donorIds <- c( - GaugedId, - donorIds[sapply(donorIds, function(x) isNodeDownstream(griwrm, x, GaugedId))] - ) - gDonor <- griwrm %>% dplyr::filter(.data$id %in% donorIds) - # Add upstream nodes for routing upstream flows - upNodes <- griwrm %>% - dplyr::filter(.data$down %in% gDonor$id, - !.data$id %in% gDonor$id) %>% - dplyr::mutate(model = ifelse(!is.na(.data$model), NA, .data$model)) - upIds <- upNodes$id - g <- rbind(upNodes, gDonor) - # Set downstream nodes - g$down[!g$down %in% g$id] <- NA + g <- getUngaugedCluster(attr(InputsModel, "GRiwrm"), GaugedId) ### Modify InputsModel for the reduced network ### # Remove nodes outside of reduced network @@ -111,6 +91,7 @@ updateParameters4Ungauged <- function(GaugedId, # Update griwrm attr(InputsModel, "GRiwrm") <- g # Update Qupstream already modeled in the reduced network upstream nodes + upIds <- attr(g, "upIds") idIM <- unique(g$down[g$id %in% upIds]) for (id in idIM) { if (useUpstreamQsim && any(InputsModel[[id]]$UpstreamIsModeled)) { diff --git a/R/utils.GRiwrm.R b/R/utils.GRiwrm.R index fb84640837790507bd03071c0016b871cd99ce5f..e4d5a4862e6f0e3986ba58c660ae6752e5b5e208 100644 --- a/R/utils.GRiwrm.R +++ b/R/utils.GRiwrm.R @@ -136,3 +136,37 @@ isNodeUpstream.GRiwrm <- function(x, current_node, candidate_node) { isNodeUpstream.GRiwrmInputsModel <- function(x, current_node, candidate_node) { isNodeUpstream(attr(x, "GRiwrm"), current_node, candidate_node) } + +#' Extract sub-network for calibration with ungauged nodes +#' +#' @inheritParams getNodeProperties +#' @param GaugedId [character], the Id of the downstream gauged node in the +#' ungauged cluster of sub-basins +#' +#' @return A [data.frame] of selected rows in `griwrm`. +#' @noRd +#' +getUngaugedCluster <- function(griwrm, GaugedId) { + ### Set the reduced network of the basin containing ungauged nodes ### + # Select nodes identified with the current node as donor gauged node + g2 <- griwrm[getDiversionRows(griwrm, TRUE), ] # Remove duplicated by Diversions + donorIds <- g2$id[!is.na(g2$donor) & g2$donor == GaugedId] + # Remove receiver nodes that haven't GaugedId as downstream node + donorIds <- c( + GaugedId, + donorIds[sapply(donorIds, function(x) isNodeDownstream(griwrm, x, GaugedId))] + ) + gDonor <- griwrm %>% dplyr::filter(.data$id %in% donorIds) + # Add upstream nodes for routing upstream flows + upNodes <- griwrm %>% + dplyr::filter(.data$down %in% gDonor$id, + !.data$id %in% gDonor$id) %>% + dplyr::mutate(model = ifelse(!is.na(.data$model), NA, .data$model)) + upIds <- upNodes$id + g <- rbind(upNodes, gDonor) + class(g) <- c("GRiwrm", class(g)) + attr(g, "upIds") <- upIds + # Set downstream nodes + g$down[!g$down %in% g$id] <- NA + return(g) +} diff --git a/tests/testthat/test-RunModel_Reservoir.R b/tests/testthat/test-RunModel_Reservoir.R index b8e1a4e326dc0c86ed29855eb19953000bf23885..e7b0b2df2e17ef129df66dd1d4471fa13753bd85 100644 --- a/tests/testthat/test-RunModel_Reservoir.R +++ b/tests/testthat/test-RunModel_Reservoir.R @@ -28,15 +28,6 @@ test_that("Calibration with Runmodel_Reservoir works!", { ErrorCrit_KGE2, RunOptions = RunOptions, Obs = Qobs[IndPeriod_Run,]) - expect_message( - CreateInputsCrit( - InputsModel, - ErrorCrit_KGE2, - RunOptions = RunOptions, - Obs = Qobs[IndPeriod_Run,] - ), - regexp = "No observations" - ) expect_warning(CreateCalibOptions(InputsModel), regexp = "FixedParam") diff --git a/tests/testthat/test-createGRiwrm.R b/tests/testthat/test-createGRiwrm.R index d8b6a7202cbd6652660875e111f37880768c5e13..e418c9f2ebef52f898534586aa6487afb3e20ce4 100644 --- a/tests/testthat/test-createGRiwrm.R +++ b/tests/testthat/test-createGRiwrm.R @@ -68,7 +68,7 @@ test_that("Derivated ungauged node without downstream node should have derivated nodes <- rbind(nodes, data.frame(id = "54001", down = "54032", length = 45, area = NA, model = "Diversion")) g <- CreateGRiwrm(nodes) - expect_equal(g$donor, rep("54032", 4)) + expect_equal(g$donor, c("54032", "54032", NA, "54032")) }) test_that("Reservoir between ungauged and gauged node should have the first downstream node as donor", { diff --git a/tests/testthat/test-getNodeRanking.R b/tests/testthat/test-getNodeRanking.R index 18ace829d7e04c0a3de79252c9b4a8e38eeea5aa..730bf128cf2eb89f058d136f4ea6f60a5dc76902 100644 --- a/tests/testthat/test-getNodeRanking.R +++ b/tests/testthat/test-getNodeRanking.R @@ -53,7 +53,8 @@ test_that("Impossible case detected: ungauged node with diversion to an upstream length = 20, model = "Diversion", area = NA)) - expect_error(CreateGRiwrm(nodes_div)) + expect_error(CreateGRiwrm(nodes_div), + regexp = "'54001' is located in the cluster") }) test_that("donor of ungauged cluster is processed before sibling ungauged nodes (#155)", {