From 63f8985dfac56659f3b807db9440b7f2520a7280 Mon Sep 17 00:00:00 2001 From: Bock <abock@usgs.gov> Date: Mon, 8 May 2023 10:04:15 -0600 Subject: [PATCH] Some minor mods, and better POI collapse --- workspace/R/NHD_navigate.R | 205 +++++++++++++++++++++++++++++++------ 1 file changed, 171 insertions(+), 34 deletions(-) diff --git a/workspace/R/NHD_navigate.R b/workspace/R/NHD_navigate.R index dfeaba0..f2d45e0 100644 --- a/workspace/R/NHD_navigate.R +++ b/workspace/R/NHD_navigate.R @@ -98,7 +98,7 @@ segment_creation <- function(nhdDF, routing_fix){ in_segs <- filter(nhdDF, !is.na(POI_ID)) # If there are routing fixes to account for if a POI with a DA of 0 is moved upsream or downstream - if (missing(routing_fix) == FALSE){ + if (!is.na(routing_fix)){ routing_fix <- routing_fix %>% rename(COMID = oldPOI, new_COMID = COMID) @@ -207,19 +207,22 @@ DS_poiFix <- function(POIs_wgeom, nhd){ #' #' @return (data frame) DF of POIs with new COMID associated movePOI_NA_DA <- function(poi_fix, nhdDF){ + print(poi_fix) + nhdDF <- distinct(nhdDF) # Closest POI/US/DS - up_segs <- nhdplusTools::get_UM(nhdDF, poi_fix, sort=T) - seg2fix <- filter(nhdDF, COMID == poi_fix) + up_segs <- unique(nhdplusTools::get_UM(nhdDF, poi_fix, sort=T)) + seg2fix <- filter(nhdDF, COMID == poi_fix) %>% + distinct() # Sorted results and filter out all flowlines w/o catchments upstuff <- filter(nhdDF, COMID %in% unlist(up_segs)) %>% - arrange(factor(COMID, levels = up_segs)) %>% + arrange(Hydroseq) %>% filter(AreaSqKM > 0) - down_segs <- nhdplusTools::get_DM(nhdDF, poi_fix, sort=T) + down_segs <- unique(nhdplusTools::get_DM(nhdDF, poi_fix, sort=T)) downstuff <- filter(nhdDF, COMID %in% unlist(down_segs)) %>% - arrange(factor(COMID, levels = down_segs)) %>% + arrange(Hydroseq)%>% filter(AreaSqKM > 0) # combine into one dataframe, select up/downstream seg with least change in total drainage area @@ -966,11 +969,16 @@ gage_POI_creation <- function(tmp_POIs, gages_info, nhd, combine_meters, reach_m gage_POIs_nonevent <- filter(gage_POIs, !Type_Gages %in% events$Type_Gages) %>% addType(., tmp_POIs, "Gages", nexus = FALSE, bind = TRUE) - tmp_POIs <- data.table::rbindlist(list(gage_POIs_nonevent, - select(events, COMID, Type_Gages, nexus)), fill = TRUE) %>% - mutate(nexus = ifelse(is.na(nexus), FALSE, nexus)) %>% - st_as_sf() - + if(nrow(events) > 0){ + tmp_POIs <- data.table::rbindlist(list(gage_POIs_nonevent, + select(events, COMID, Type_Gages, nexus)), fill = TRUE) %>% + mutate(nexus = ifelse(is.na(nexus), FALSE, nexus)) %>% + st_as_sf() + } else { + events <- NA + tmp_POIs <- mutate(tmp_POIs, nexus = FALSE) + } + return(list(events = events, tmp_POIs = tmp_POIs)) } @@ -985,7 +993,7 @@ gage_POI_creation <- function(tmp_POIs, gages_info, nhd, combine_meters, reach_m #' wbout_POI_creaton <- function(nhd, WBs_VPU, data_paths, crs){ # Create waterbody outlet POIs for waterbodies that are in NHDv2 waterbody set - wbout_COMIDs <- filter(nhd, dend == 1 & WB == 1) %>% + wbout_COMIDs <- nhd %>% #filter(nhd, dend == 1 & WB == 1) group_by(WBAREACOMI) %>% slice(which.min(Hydroseq)) %>% switchDiv(., nhd) %>% @@ -1074,7 +1082,7 @@ wbin_POIcreation <- function(nhd, WBs_VPU, data_paths, crs, filter(minNet == 1) # Headwater Waterbodies that may need the network extended through the inlet - need_wbin <- st_drop_geometry(filter(WBs_VPU, source == "NHDv2WB")) %>% + need_wbin <- st_drop_geometry(filter(WBs_VPU, source %in% c("ref_WB", "NHDv2WB"))) %>% dplyr::select(COMID)%>% dplyr::filter(!COMID %in% wbin_COMIDs$WBAREACOMI) @@ -1151,7 +1159,7 @@ wbin_POIcreation <- function(nhd, WBs_VPU, data_paths, crs, mutate(dsCOMID = COMID, COMID = usCOMID) if(nrow(wb_inlet_POIs) > 0) { - wbin_POIs <- bind_rows(wbin_POIs, POI_creation(select(st_drop_geometry(wb_inlet_POIs), dsCOMID, Type_WBIn = WBAREACOMI), + wbin_POIs <- bind_rows(wbin_POIs, POI_creation2(select(st_drop_geometry(wb_inlet_POIs), dsCOMID, Type_WBIn = WBAREACOMI), nhd, "WBIn")) wb_inlet_events <- filter(wb_inlet_events, !COMID %in% wb_inlet_POIs$dsCOMID) @@ -1208,7 +1216,7 @@ wb_inlet_collapse <- function(tmp_POIs, nhd, events){ unique() if(nrow(gage_reach) == 0){ - print("Wilton") + print("no gage reaches") } if(nrow(gage_event) == 0){ @@ -1333,11 +1341,9 @@ wb_inlet_collapse <- function(tmp_POIs, nhd, events){ #' @param events (sf data.frame) waterbody inlet events #' #' @return (sf data.frame) dataframe of wb inlet POIs collapse -#' -#' wb_poi_collapse <- function(tmp_POIs, nhd, events){ wb_poi_collapse <- function(tmp_POIs, nhd, events){ gage_dist_node <- function(x, wb_ds_ds, gage_add, events){ - print (x) + print (x) #6116850 wb_out_fl <- filter(wb_ds_ds, COMID == x) gage_ds <- filter(wb_ds_ds, Hydroseq %in% wb_out_fl$Hydroseq | Hydroseq %in% wb_out_fl$DnHydroseq) @@ -1353,15 +1359,14 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ unique() if(nrow(gage_reach) == 0){ - print("Wilton") + print("no gages") } if(nrow(gage_event) == 0){ - #print("akermayun") - return("Akermayun") + return("no events") } else if(gage_event$COMID != wb_out_fl$COMID) { gage_reach <- gage_reach %>% - filter(REACHCODE == gage_event$reachcode) %>% + filter(REACHCODE == unique(gage_event$reachcode)) %>% mutate(gage_dist = ifelse(gage_event$nexus == TRUE, total_length * (1 - (gage_event$reach_meas/100)), total_length)) %>% @@ -1369,10 +1374,10 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ wbout_comid = x) } else if(gage_event$COMID == wb_out_fl$COMID){ if(nrow(wb_event) >0){ - wb_out_meas <- wb_event$REACH_meas + wb_out_meas <- min(wb_event$REACH_meas) wb_RC <- wb_event$REACHCODE } else { - wb_out_meas <- wb_out_fl$FromMeas + wb_out_meas <- min(wb_out_fl$FromMeas) wb_RC <- wb_out_fl$REACHCODE } @@ -1383,7 +1388,7 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ # wb info wb_reach <- gage_reach %>% - filter(REACHCODE == wb_RC) %>% + filter(REACHCODE == unique(wb_RC)) %>% mutate(wb_dist = total_length * (1 - (wb_out_meas /100))) gage_reach <- gage_reach %>% @@ -1393,14 +1398,11 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ } } - #events <- read_sf(temp_gpkg, split_layer) %>% - # rbind(st_compatibalize(wb_,.)) # Previously identified streamgages within Gage_Selection.Rmd streamgages_VPU <- gages %>% rename(COMID = comid) %>% filter(COMID %in% nhd$COMID) %>% - #st_drop_geometry() %>% switchDiv(., nhd) # get waterbody outlets @@ -1421,10 +1423,16 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ gage_add <- filter(streamgages_VPU, site_no %in% gage_wb$Type_Gages) %>% select(COMID, reachcode, reach_meas, site_no) %>% inner_join(select(st_drop_geometry(gage_wb), site_no = Type_Gages, nexus), - by = "site_no") + by = "site_no") %>% + distinct() output <- lapply(wb_out$COMID, gage_dist_node, wb_ds_ds, gage_add, events) + output_length <- output[lengths(output) > 1] + + if(length(output_length) == 0){ + return(list(POIs = tmp_POIs, events_ret = NA)) + } output_full <- do.call("rbind", output[lengths(output) > 1]) %>% filter(gage_dist < 1) %>% @@ -1438,12 +1446,11 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ gage_POI <- filter(tmp_POIs, COMID %in% output_full$gage_comid) %>% select(COMID, Type_HUC12_ds = Type_HUC12, Type_Gages_ds = Type_Gages, - Type_TE_ds = Type_TE, Type_Term_ds = Type_Term, nexus) %>% + Type_TE_ds = Type_TE, nexus) %>% st_drop_geometry() %>% group_by(COMID) %>% summarise(Type_HUC12_ds = last(na.omit(Type_HUC12_ds)), Type_Gages_ds = last(na.omit(Type_Gages_ds)), - Type_Term_ds = last(na.omit(Type_Term_ds)), Type_TE_ds = last(na.omit(Type_TE_ds)), nexus = last(na.omit(nexus))) @@ -1452,9 +1459,8 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ inner_join(select(gage_POI, -nexus), by = c("gage_comid" = "COMID")) %>% mutate(Type_HUC12 = ifelse(!is.na(Type_HUC12_ds), Type_HUC12_ds, Type_HUC12), Type_Gages = ifelse(!is.na(Type_Gages_ds), Type_Gages_ds, Type_Gages), - Type_TE = ifelse(!is.na(Type_TE_ds), Type_TE_ds, Type_TE), - Type_Term = ifelse(!is.na(Type_Term_ds), Type_Term_ds, Type_Term)) %>% - select(-c(Type_HUC12_ds, Type_Gages_ds, Type_TE_ds, Type_Term_ds)) + Type_TE = ifelse(!is.na(Type_TE_ds), Type_TE_ds, Type_TE)) %>% + select(-c(Type_HUC12_ds, Type_Gages_ds, Type_TE_ds)) tmp_POIs_fin <- filter(tmp_POIs, !COMID %in% c(WB_POI$COMID, WB_POI$gage_comid)) %>% rbind(select(WB_POI, -gage_comid)) @@ -1466,4 +1472,135 @@ wb_poi_collapse <- function(tmp_POIs, nhd, events){ return(list(POIs = tmp_POIs_fin, events_ret = events)) +} + +#' Creates Waterbody POIs, calls a few other functions +#' @param (pois) sf data frame of POIs +#' @param move_category (character) POI data theme to move +#' @param DAR (numeric) drainage area threshold to move within +#' @param dist (numeric) maximum river distance between two points to move within +#' @param keep_category (character) POI data themes to keep static +#' +#' @return (sf data.frame, table) dataframe of pois, table of points that have moved +poi_move <- function(pois, move_category, DAR, dist, keep_category) { + # filter out features with identical geometry + + # Add row_number + pois_edit <- pois %>% + mutate(nexus = ifelse(is.na(nexus), 0, nexus)) + + # Don't consider points already moved + if("moved" %in% colnames(pois_edit)){ + pois_tomove <- filter(pois_edit, is.na(moved)) # change from poi_edit + pois_moved_pre <- filter(pois_edit, !is.na(moved))} + + # If 'keep' category included + if(!missing(keep_category)){ + poi2move <- filter(pois_tomove, !is.na(.data[[move_category]]) & nexus == FALSE) %>% + filter(if_all(!!as.symbol(keep_category), function(x) is.na(x))) %>% + # Never move these + filter_at(vars(Type_WBOut, Type_WBIn, Type_Conf, Type_Term), all_vars(is.na(.))) + + pois2keep <- filter(pois_tomove, !id %in% poi2move$id) + #is.na(.data[[move_category]]) & nexus == FALSE) #%>% + #filter(if_all(!!as.symbol(keep_category), function(x) is.na(x))) + } else { + # POIs to move + poi2move <- pois_tomove %>% + filter_at(vars(Type_WBOut, Type_WBIn, Type_Conf, Type_Term), all_vars(is.na(.))) %>% + filter(nexus == 0) %>% + filter(!is.na(.data[[move_category]])) + + pois2keep <- filter(pois_tomove, !id %in% poi2move$id) + } + + # Get relevant NHD data + nhd_poi1 <- filter(nhd, COMID %in% pois2keep$COMID) + nhd_poi2 <- filter(nhd, COMID %in% poi2move$COMID) + # Ensure they are on same level path + nhd_poi2 <- filter(nhd_poi2, LevelPathI %in% nhd_poi1$LevelPathI) + + # Join NHD data + pois2keep_nhd <- pois2keep %>% + inner_join(select(st_drop_geometry(nhd_poi1), COMID, LevelPathI, Hydroseq, + DA_keep = TotDASqKM, Pathlength_keep = Pathlength), by = "COMID") %>% + rename(COMID_keep = COMID) + + # Join NHD data + pois2move_nhd <- select(poi2move, COMID, !!as.symbol(move_category), id_move = id) %>% + inner_join(select(st_drop_geometry(nhd_poi2), COMID, LevelPathI, Hydroseq, TotDASqKM, Pathlength), + by = "COMID") + + # Candidates to move + pois2move_cand <-pois2move_nhd %>% + inner_join(select(st_drop_geometry(pois2keep_nhd), COMID_keep, DA_keep, LevelPathI, + Pathlength_keep, id_keep = id, nexus), + by = "LevelPathI") %>% + mutate(river_dist = abs(Pathlength - Pathlength_keep), DAR_poi = abs(DA_keep/TotDASqKM), + move_dir = ifelse(Pathlength < Pathlength_keep, "Up", "Down")) %>% + group_by(id_move, move_dir) %>% + ungroup() %>% + filter((river_dist < dist) & (DAR_poi > (1 - DAR)) & (DAR_poi < (1 + DAR))) %>% + select(!!as.symbol(move_category), id_move, COMID, id_keep, COMID_keep, river_dist, DAR_poi, move_dir, nexus) %>% + st_drop_geometry() + + move_distinct <- pois2move_cand %>% + group_by(id_keep) %>% + filter(row_number() == 1) %>% + ungroup() %>% + distinct(id_move, COMID_move = COMID, id_keep, COMID_keep, river_dist, DAR_poi, move_dir, nexus) %>% + group_by(id_move) %>% + slice(which.min(abs(1 - DAR_poi))) + + if(nrow(move_distinct) == 0){ + print("no POIs to move") + return(pois) + } + + pois2_move <- filter(st_drop_geometry(pois_tomove), id %in% move_distinct$id_move) %>% + select_if(~sum(!is.na(.)) > 0) %>% + select(-c(COMID, nexus)) %>% + inner_join(select(move_distinct, id_move, id_keep), by = c("id" = "id_move")) + + move_fields <- colnames(select(pois2_move, -c(id, id_keep))) + + if(length(move_fields) == 1){ + pois2_keep <- filter(pois_tomove, id %in% pois2_move$id_keep, !id %in% pois2_move$id) %>% + inner_join(select(pois2_move, id_move = id, id_keep, + new_val = !!as.symbol(move_category)), by = c("id" = "id_keep")) %>% + mutate(moved := ifelse(is.na(!!as.symbol(move_category)), + id_move, moved), + !!as.symbol(move_category) := ifelse(is.na(!!as.symbol(move_category)), + new_val, !!as.symbol(move_category))) + + moved_points <- filter(pois2_keep, !is.na(new_val), !is.na(moved)) %>% + mutate(moved_value = move_category) + } else { + for (field in move_fields){ + pois2_keep <- filter(pois_tomove, id %in% pois2_move$id_keep, !id %in% pois2_move$id) %>% + inner_join(select(pois2_move, id_move = id, id_keep, new_val = !!as.symbol(field)), + by = c("id" = "id_keep")) %>% + mutate(moved := ifelse(is.na(!!as.symbol(field)), + id_move, moved), + !!as.symbol(field) := ifelse(is.na(!!as.symbol(field)), + new_val, !!as.symbol(field))) + + pois_moved <- filter(pois2_keep, !is.na(new_val), !is.na(moved)) %>% + mutate(moved_value = field) + + if(!exists("moved_points")){ + moved_points <- pois_moved + } else { + moved_points <- rbind(moved_points, pois_moved) + } + } + } + + + pois_final <- data.table::rbindlist(list(filter(pois_edit, !id %in% c(moved_points$id_move, pois2_keep$id)), + select(pois2_keep, -c(new_val, id_move, new_val))), fill = TRUE) %>% + st_as_sf() + + return(list(final_pois = pois_final, moved_points = moved_points)) + } \ No newline at end of file -- GitLab