diff --git a/workspace/R/02_POI_creation_functions.R b/workspace/R/02_POI_creation_functions.R
index e4ed26080afd29fd50a9d98b3448783d54eacf2c..aa89549ac23c9dd7b847b5e647b88551196a97de 100644
--- a/workspace/R/02_POI_creation_functions.R
+++ b/workspace/R/02_POI_creation_functions.R
@@ -1393,10 +1393,12 @@ create_wb_inlet_pois <- function(tmp_POIs, wb_lyr, events,
   if(!all(is.na(wb_layers$events))) {
     wb_inlet_events <- wb_layers$events %>%
       select(COMID, REACHCODE, REACH_meas, POI_identifier,
-             event_type, nexus) 
+             event_type, nexus)
+    
+    events <- rbind(events, st_compatibalize(wb_inlet_events, events))
   }
   
-  list(tmp_POIs = wb_in_col$POIs, wb_inlet_events = wb_inlet_events)
+  list(tmp_POIs = wb_in_col$POIs, events = events)
 }
 
 ### used as part of waterbody poi creation in the workflow
@@ -1738,7 +1740,7 @@ create_time_of_travel_pois <- function(tmp_POIs, flowline, all_nhdplus_attribute
   #TODO Add magic numbers to config file
   tt_splits <- tt_pois_split %>%
     st_drop_geometry() %>%
-    group_by(POI_ID) %>%ave
+    group_by(POI_ID) %>%
     arrange(-Hydroseq) %>%
     mutate(ind = cs_group(FL_tt_hrs, travt_diff * 0.75)) %>%
     ungroup() %>%
@@ -1757,4 +1759,665 @@ create_time_of_travel_pois <- function(tmp_POIs, flowline, all_nhdplus_attribute
   
   list(tmp_POIs = tmp_POIs)
   
+}
+
+#' create final POIs
+#' @param tmp_POIs POIs from previous step
+#' @param flowline flowlines to attach pois to
+create_final_pois <- function(tmp_POIs, flowline) {
+
+  unCon_POIs <- filter(tmp_POIs, COMID %in% filter(flowline, AreaSqKM == 0)$COMID)
+  
+  xWalk <- NULL
+  new_POIs <- NULL
+  
+  # If any POIs happened to fall on flowlines w/o catchment
+  if (nrow(unCon_POIs) > 0){
+    # For confluence POIs falling on Flowlines w/o catchments, derive upstream valid flowline,
+    poi_fix <- DS_poiFix(tmp_POIs, filter(flowline, minNet == 1))
+    new_POIs <- st_compatibalize(poi_fix$new_POIs, tmp_POIs)
+    xWalk <- poi_fix$xWalk
+    
+    # POIs that didn't need to be moved
+    tmp_POIs_fixed <- filter(tmp_POIs, nexus == TRUE | 
+                               !COMID %in% c(poi_fix$xWalk$oldPOI, poi_fix$xWalk$COMID))
+    # bind together
+    final_POIs <- bind_rows(tmp_POIs_fixed, new_POIs) %>%
+      mutate(Type_Term = ifelse(nexus == 1, NA, Type_Term)) %>%
+      select(-dplyr::any_of(c("ID")))
+    
+  } else {
+    # If no fixes designate as NA
+    poi_fix <- NA
+    
+    tmp_POIs$nexus <- as.integer(tmp_POIs$nexus)
+    
+    # if a POI will be a nexus, it can not be terminal.
+    final_POIs <- mutate(tmp_POIs, Type_Term = ifelse(nexus == 1, NA, Type_Term))
+    
+  }
+ 
+  list(final_POIs = final_POIs, xwalk = xWalk, new_POIs = new_POIs, 
+       unCon_POIs = unCon_POIs) 
+}
+
+### used as a cleanup step in POI workflow
+#' Moves POI Upstream or downstream if it falls on COMID
+#       of flowline with no corresponding catchment
+#'  @param POIs_wgeom (sf data.frame) POIs
+#'  @param nhdDF  (sf data.frame) valid data frame of NHD flowlines
+#' 
+#' @return (sf data.frame) data.frame of POIs with new COMID associated
+DS_poiFix <- function(POIs_wgeom, nhd){
+  nhd <- distinct(nhd)
+  POIs <- st_drop_geometry(POIs_wgeom) %>%
+    arrange(COMID) %>%
+    filter(nexus == FALSE)
+  
+  # DF of downstream segment
+  tocomDF <- select(st_drop_geometry(nhd), COMID, Hydroseq, TotDASqKM,
+                    DnHydroseq, WBAREACOMI) %>%
+    inner_join(select(st_drop_geometry(nhd), COMID_ds = COMID, Hydroseq, 
+                      WBAREACOMI_down = WBAREACOMI, totda_ds = TotDASqKM), 
+               by = c("DnHydroseq" = "Hydroseq")) %>%
+    inner_join(select(st_drop_geometry(nhd), COMID_us = COMID, DnHydroseq,
+                      WBAREACOMI_up = WBAREACOMI, totda_us = TotDASqKM),
+               by = c("Hydroseq" = "DnHydroseq"))
+  
+  # Find segments with POIs where there is no corresponding catchment that are not terminal
+  unCon_fl <- filter(nhd, COMID %in% POIs$COMID, AreaSqKM == 0)# & Hydroseq != TerminalPa)
+  unCon_POIs <- filter(POIs, COMID %in% unCon_fl$COMID)
+  
+  # Get specific fixes for waterbody inlets and outlets
+  wbout <- filter(unCon_POIs, !is.na(Type_WBOut)) %>%
+    inner_join(tocomDF, by = "COMID") %>%
+    mutate(nonrefactor = ifelse(WBAREACOMI %in% WBAREACOMI_up, COMID_ds, 0),
+           new_POI = COMID_us)
+  
+  wb_pois <- filter(unCon_POIs, !is.na(Type_WBIn)) %>%
+    inner_join(tocomDF, by = "COMID") %>%
+    mutate(nonrefactor = ifelse(WBAREACOMI < 0, COMID_ds, 0),
+           new_POI = COMID_us) %>%
+    rbind(wbout) %>%
+    select(-c(nexus, Hydroseq, TotDASqKM, DnHydroseq, WBAREACOMI, COMID_ds,
+              WBAREACOMI_down, totda_ds, COMID_us, WBAREACOMI_up, totda_us)) %>%
+    rename(COMID = new_POI, oldPOI = COMID)
+  
+  # The rest can be resolved with drainage are ratio
+  unCon_POIs <- filter(unCon_POIs, !COMID %in% wb_pois$oldPOI)
+  
+  poi_fix <- as.data.frame(do.call("rbind", lapply(unCon_POIs$COMID, movePOI_NA_DA, st_drop_geometry(nhd)))) %>%
+    inner_join(POIs, by = c("oldPOI" = "COMID")) %>%
+    inner_join(select(st_drop_geometry(nhd), COMID), by = c("oldPOI" = "COMID")) %>%
+    select(-c(AreaSqKM, DnHydroseq, nexus, TotDASqKM)) %>%
+    distinct() %>%
+    bind_rows(wb_pois)
+  
+  # Fold in new POIs with existing POIs so all the "Type" attribution will carry over
+  # using the minimum will ensure correct downstream hydrosequence gets carried over
+  poi_orig <- filter(POIs, COMID %in% poi_fix$COMID) %>%
+    bind_rows(poi_fix) %>%
+    select(-oldPOI)
+  
+  list_df <- dplyr::group_by(poi_orig, COMID) |>
+    group_split()
+  
+  compact <- function(l) {
+    if(nrow(l) == 1) return(as.data.frame(l))
+    lapply(names(l), \(x) {
+      out <- unique(l[[x]][!is.na(l[[x]])])
+      if(!length(out)) NA 
+      else if(length(out) == 1) out 
+      else {
+        cat(paste("duplicate id for", unique(l$COMID),
+                  "column", x, 
+                  "values", paste(out, collapse = ", "), 
+                  "using", out[1]), file = "POI-issues.log")
+        out[1]
+      }
+    }) |> 
+      setNames(names(l)) |>
+      as.data.frame()
+  }
+  
+  poi_merged <- bind_rows(lapply(list_df, compact))
+  
+  # # Combine POI information together for redundant pois  
+  # poi_merged <- poi_orig %>% 
+  #   select(-c(nexus, AreaSqKM, oldPOI, DnHydroseq, TotDASqKM)) %>%
+  #   group_by(COMID) %>%
+  #   summarise_each(funs(toString(na.omit(.)))) 
+  # is.na(poi_merged) <- poi_merged == ""
+  
+  # Join new POI COMIDs and geometry with the old Type fields
+  fin_POIs <- poi_merged %>%
+    arrange(COMID) %>%
+    bind_cols(get_node(filter(nhd, COMID %in% .$COMID) %>% arrange(COMID), position = "end")) %>%
+    st_sf() %>%
+    st_compatibalize(., POIs_wgeom)
+  
+  return (list(xWalk = poi_fix, new_POIs = fin_POIs))
+}
+
+### USED in DS_poiFix
+#' Move POIs that fall on flowlines with no catchment upstream/downstream
+#     to adjacent flowline with most similar total drainage area. Called from 
+#     DS_poi_fix function above
+#'  @param poi_fix (data.frame) POI data set of COMIDs to be changed
+#'  @param nhdDF  (sf data.frame) valid data frame of NHD flowlines
+#' 
+#' @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 <- 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(Hydroseq) %>%
+    filter(AreaSqKM > 0)
+  
+  down_segs <- unique(nhdplusTools::get_DM(nhdDF, poi_fix, sort=T))
+  downstuff <- filter(nhdDF, COMID %in% unlist(down_segs)) %>% 
+    arrange(Hydroseq)%>%
+    filter(AreaSqKM > 0)
+  
+  # combine into one dataframe, select up/downstream seg with least change in total drainage area
+  near_FL <- rbind(select(upstuff, COMID, TotDASqKM, AreaSqKM) %>% 
+                     slice(1), 
+                   select(downstuff, COMID, TotDASqKM, AreaSqKM) %>% 
+                     slice(1))
+  
+  # If 1 or other adjacent flowlines are coupled with a catchment
+  if (sum(near_FL$AreaSqKM) > 0){
+    new_POI <- near_FL[(which.min(abs(seg2fix$TotDASqKM - near_FL$TotDASqKM))),] #near_FL$COMID
+    new_POI$oldPOI <- poi_fix
+    new_POI$DnHydroseq <-seg2fix$DnHydroseq
+  } else {
+    # Remove POI if not catchment associated with flowlines upstream or downstream
+    print (poi_fix)
+    print ("US and DS flowlines also have no catchment, removing POI")
+    new_POI <- NA
+  }
+  return(new_POI)
+}
+
+#' create draft segments
+#' @param final_POIs POIs from previous step
+#' @param flowline flowlines to attach pois to
+create_draft_segments <- function(final_POIs, flowline, xWalk) {
+
+  if("POI_ID" %in% colnames(flowline)) {
+    flowline <- select(flowline, -POI_ID)
+  }
+  
+  # Sort POIs by Levelpath and Hydrosequence in upstream to downstream order
+  seg_POIs <-  filter(st_drop_geometry(flowline),  
+                      COMID %in% final_POIs$COMID, 
+                      COMID %in% filter(flowline,  minNet == 1)$COMID)
+
+  # derive incremental segments from POIs
+  inc_segs <- make_incremental_segments(filter(flowline,  minNet == 1), seg_POIs)
+  
+  flowline_final <- flowline %>%
+    left_join(select(inc_segs, COMID, POI_ID), by = "COMID")
+  
+  # create and write out final dissolved segments
+  nsegments_fin <- segment_creation(flowline_final, xWalk)
+  
+  flowline_final <- select(flowline_final, -POI_ID) %>%
+    left_join(distinct(st_drop_geometry(nsegments_fin$raw_segs), COMID, POI_ID), by = "COMID")
+  
+  nsegments <- nsegments_fin$diss_segs
+  
+  list(flowline_final = flowline_final, nsegments = nsegments)
+  
+}
+
+#' Creates finalized segments and routing
+#'  @param nhdDF (sf data.frame) valid data frame of NHD flowlines
+#'  @param routing_fix  (sf data.frame) any additional routing fixes
+#' 
+#' @return (sf data.frame) data.frame of segments
+segment_creation <- function(nhdDF, routing_fix = NULL){ 
+  
+  if(!"StartFlag" %in% names(nhdDF)) {
+    nhdDF$StartFlag <- ifelse(nhdDF$Hydroseq %in% nhdDF$DnHydroseq, 0, 1)
+  }
+  
+  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 (is.data.frame(routing_fix)){
+    routing_fix <- routing_fix %>%
+      rename(COMID = oldPOI, new_COMID = COMID)
+    
+    # Above we generated the network using the initial set of POIs; here we crosswalk over the old COMIDs to the new
+    nhd_fix <- nhdDF %>%
+      left_join(routing_fix %>%
+                  select(COMID, new_COMID), by = c("POI_ID" = "COMID")) %>%
+      mutate(POI_ID = ifelse(is.na(new_COMID), POI_ID, new_COMID)) %>%
+      filter(!POI_ID %in% routing_fix$COMID) %>%
+      select(-new_COMID)
+    
+    in_segs <- filter(nhd_fix, !is.na(POI_ID))
+  }
+  
+  # Dissolve flowlines to aggregated segments
+  nsegments <- filter(in_segs, !is.na(POI_ID)) %>%
+    group_by(POI_ID) %>%
+    #arrange(desc(LevelPathI), desc(Hydroseq)) %>%
+    summarize(TotalLength = sum(LENGTHKM),TotalDA = max(TotDASqKM), HW = max(StartFlag),
+              do_union = FALSE) %>%
+    #st_cast("MULTILINESTRING")  %>%
+    inner_join(st_drop_geometry(filter(in_segs, minNet == 1)) %>%
+                 select(COMID, Hydroseq, DnHydroseq), by = c("POI_ID" = "COMID"))
+  
+  # produce a short data frame for populating TO_POI for downstream segment
+  to_from <- filter(st_drop_geometry(in_segs)) %>%
+    left_join(filter(st_drop_geometry(nhdDF), !is.na(POI_ID)) %>% 
+                select(COMID, Hydroseq, POI_ID), by = c("DnHydroseq" = "Hydroseq")) %>%
+    select(COMID.x, Hydroseq, DnHydroseq, POI_ID.y) %>%
+    rename(To_POI_ID = POI_ID.y) 
+  
+  # Add To_POI_ID to dissolved segments
+  nsegments_fin <- nsegments %>% 
+    left_join(select(to_from, COMID.x, To_POI_ID), by = c("POI_ID" = "COMID.x")) %>%
+    select(POI_ID, TotalLength, TotalDA, HW, To_POI_ID) 
+  
+  return(list(diss_segs = nsegments_fin, raw_segs = in_segs))
+}
+
+collapse_pois <- function(final_POIs, poi_dar_move, poi_distance_move, flowline) {
+
+  # number POIs
+  final_POIs_prec <- mutate(final_POIs, id = row_number(), moved = NA)
+  
+  collapse <- TRUE
+  
+  moved_pois <- get_moved_pois(final_POIs_prec, poi_dar_move, poi_distance_move, flowline)
+  
+  check_dups <- moved_pois$final_POIs %>%
+    group_by(COMID) %>%
+    filter(n() > 1) 
+  
+  dups <- NULL
+  
+  if(nrow(filter(check_dups, all(c(0,1) %in% nexus))) != nrow(check_dups)){
+    print("Multiple POI ids at same geometric location")
+    no_dups <- filter(check_dups, all(c(0,1) %in% nexus))
+    dups <- filter(check_dups, !id %in% no_dups$id)
+    # write_sf(dups, temp_gpkg, dup_pois)
+  } else {
+    print("All double COMIDs nexus for gage or WB splitting")
+  }
+  
+  list(final_POIs = final_POIs_prec, 
+       duplicate_pois = dups, 
+       pois_collapsed = moved_pois$pois_collapsed)
+}
+
+### used when poi_move.R is sourced in POI collapse phase of workflow
+### consider calling at the end of each poi creation process?
+#'  Collapses POIs together based on criteria
+#'  @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 flowline (sf data.frame) nhd flowline
+#'  @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, flowline, 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(flowline, COMID %in% pois2keep$COMID)
+  nhd_poi2 <- filter(flowline, 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))
+  
+}
+
+
+#' get moved pois
+#' @param final_POIs finalized POIs that can be reconciled
+#' @param poi_dar_move POI drainage area ratio where moves are allowed
+#' @param poi_distance_move POI distance where moves are allowed
+#' @param flowline flowline to use for evaluation of poi moves 
+get_moved_pois <- function(final_POIs, poi_dar_move, poi_distance_move, flowline) {
+  
+  # Move HUC12 to other POIs
+  moved_pois <- poi_move(final_POIs, "Type_HUC12", poi_dar_move, 
+                         poi_distance_move, flowline) 
+  
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois$moved_points %>%
+      mutate(move_type = "huc12 to other")
+  } else {
+    final_POIs <- moved_POIs
+  }
+  
+  # Gages to confluences, terminals
+  moved_pois <- poi_move(final_POIs, "Type_Gages", poi_dar_move, 
+                         poi_distance_move, flowline, c("Type_Conf", "Type_Term"))
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois_table %>%
+      rbind(moved_pois$moved_points %>%
+              mutate(move_type = "gages to conf"))
+  } else {
+    final_POIs <- moved_POIs
+  }
+  
+  # Gages to waterbody inlets
+  moved_pois <- poi_move(final_POIs, "Type_Gages", poi_dar_move, 
+                         poi_distance_move, flowline, c("Type_WBIn", "Type_WBOut")) 
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois_table %>%
+      rbind(moved_pois$moved_points %>%
+              mutate(move_type = "gages to wbin"))
+  } else {
+    final_POIs <- moved_pois
+  }
+  
+  # Waterbody inlet to confluence
+  moved_pois <- poi_move(final_POIs, "Type_WBIn", poi_dar_move/2, 
+                         poi_distance_move*0.4, flowline, "Type_Conf")
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois_table %>%
+      rbind(moved_pois$moved_points %>%
+              mutate(move_type = "gages to term"))
+  } else {
+    final_POIs <- moved_pois
+  }
+  
+  # # Waterbody inlet to confluence
+  # moved_pois <- poi_move(final_POIs, "Type_WBOut", poi_dar_move/2, 
+  #                        poi_distance_move*0.4, flowline, "Type_WBIn")
+  # if(!is.data.frame(moved_pois)){
+  #   final_POIs <- moved_pois$final_pois
+  #   moved_pois_table <- moved_pois_table %>%
+  #     rbind(moved_pois$moved_points %>%
+  #             mutate(move_type = "gages to term"))
+  # } else {
+  #   final_POIs <- moved_pois
+  # }
+  
+  # Waterbody inlet to confluence
+  # TODO: verify that this is OK Type_HUC12 was here in move_category?!?
+  moved_pois <- poi_move(final_POIs, "Type_WBIn", poi_dar_move/2, 
+                         poi_distance_move*0.4, flowline, "Type_Conf")
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois_table %>%
+      rbind(moved_pois$moved_points %>%
+              mutate(move_type = "gages to term"))
+  } else {
+    final_POIs <- moved_pois
+  }
+  
+  # NID to waterbody outlet
+  moved_pois <- poi_move(final_POIs, "Type_hilarri", poi_dar_move/2, 
+                         poi_distance_move * 0.4, flowline, c("Type_WBOut", "Type_TE"))
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois_table %>%
+      rbind(moved_pois$moved_points %>%
+              mutate(move_type = "nid to wb_out"))
+  } else {
+    final_POIs <- moved_pois
+  }
+  
+  # NID to waterbody outlet
+  moved_pois <- poi_move(final_POIs, "Type_DA", poi_dar_move, 
+                         poi_distance_move, flowline)
+  if(!is.data.frame(moved_pois)){
+    final_POIs <- moved_pois$final_pois
+    moved_pois_table <- moved_pois_table %>%
+      rbind(moved_pois$moved_points %>%
+              mutate(move_type = "nid to wb_out"))
+  } else {
+    final_POIs <- moved_pois
+  }
+  
+  if("Type_elev" %in% names(final_POIs)){
+    # NID to waterbody outlet
+    moved_pois <- poi_move(final_POIs, "Type_elev", poi_dar_move, 
+                           poi_distance_move, flowline)
+    if(!is.data.frame(moved_pois)){
+      final_POIs <- moved_pois$final_pois
+      moved_pois_table <- moved_pois_table %>%
+        rbind(moved_pois$moved_points %>%
+                mutate(move_type = "nid to wb_out"))
+    } else {
+      final_POIs <- moved_pois
+    }
+  }
+  
+  list(final_POIs = final_POIs, pois_collapsed = moved_pois_table)
+  
+} 
+
+create_poi_lookup <- function(final_POIs, events, full_cats, 
+                              flowline, pois_collapsed) {
+
+  # Final POI layer
+  POIs <- final_POIs %>%
+    mutate(identifier = row_number())
+  
+  # Unique POI geometry
+  final_POI_geom <- POIs %>%
+    select(identifier) %>%
+    cbind(st_coordinates(.)) %>%
+    group_by(X, Y) %>%
+    mutate(geom_id = cur_group_id()) %>%
+    ungroup()
+  
+  final_POIs_table <- POIs %>%
+    inner_join(select(st_drop_geometry(final_POI_geom), -X, -Y), by = "identifier")  %>%
+    select(-identifier) 
+  
+  # POI data theme table
+  pois_data_orig <- reshape2::melt(st_drop_geometry(select(final_POIs_table,
+                                                           -c(nexus, nonrefactor, id, moved))),
+                                   id.vars = c("COMID", "geom_id")) %>%
+    filter(!is.na(value)) %>%
+    group_by(COMID, geom_id) %>%
+    mutate(identifier = cur_group_id()) %>%
+    rename(hy_id = COMID, poi_id = identifier, hl_reference = variable, hl_link = value) %>%
+    distinct() 
+  
+  if(!is.null(pois_collapsed)){
+    pois_data_moved <- select(st_drop_geometry(pois_collapsed), 
+                              hy_id = COMID, hl_link = new_val, hl_reference = moved_value) %>%
+      inner_join(distinct(pois_data_orig, hy_id, geom_id, poi_id), by = "hy_id") 
+    
+    pois_data <- data.table::rbindlist(list(pois_data_moved, pois_data_orig), use.names = TRUE) %>%
+      filter(!hl_reference %in% c("id", "moved"))
+  } else {
+    pois_data <- pois_data_orig
+  }
+  
+  # POI Geometry table
+  poi_geometry <- select(final_POIs_table, hy_id = COMID, geom_id) %>%
+    inner_join(distinct(pois_data, hy_id, geom_id, poi_id),
+               by = c("hy_id" = "hy_id", "geom_id" = "geom_id")) %>%
+    distinct() %>%
+    st_as_sf()
+  
+  # write_sf(pois_data, nav_gpkg, poi_data_table)
+  # write_sf(poi_geometry, nav_gpkg, poi_geometry_table)
+  
+  poi_geom_xy <- cbind(poi_geometry, st_coordinates(poi_geometry)) %>%
+    st_drop_geometry()
+  
+  event_table <- NULL
+  
+  if(!is.null(events)) {
+    events_data <- events %>%
+      arrange(COMID) %>%
+      cbind(st_coordinates(.)) %>%
+      st_drop_geometry() %>%
+      group_by(COMID, REACHCODE, REACH_meas) %>%
+      mutate(event_id = cur_group_id()) %>%
+      rename(hy_id = COMID) %>%
+      ungroup()
+    
+    event_table <- select(events_data, -c(nexus, X, Y))
+  }
+  
+  nexi <- filter(final_POIs_table, nexus == 1) %>%
+    cbind(st_coordinates(.)) %>%
+    select(hy_id = COMID, X, Y) %>%
+    inner_join(poi_geom_xy, by = c("hy_id" = "hy_id", "X" = "X", "Y" = "Y")) %>%
+    inner_join(events_data, by = c("hy_id" = "hy_id", "X" = "X", "Y" = "Y"), multiple = "all") %>%
+    select(hy_id, REACHCODE, REACH_meas, event_id, poi_id) %>%
+    group_by(hy_id, REACHCODE) %>%
+    filter(REACH_meas == min(REACH_meas)) %>%
+    ungroup()
+  #distinct(hy_id, REACHCODE, REACH_meas, event_id, poi_id)
+  
+  event_geometry_table <- nexi
+  
+  # write_sf(, nav_gpkg, event_table)
+  # write_sf(nexi, nav_gpkg, event_geometry_table)
+  
+  #  Load data
+    # full_cats <- readRDS(data_paths$fullcats_table)
+    
+    lookup <- dplyr::select(sf::st_drop_geometry(flowline),
+                            NHDPlusV2_COMID = COMID,
+                            realized_catchmentID = COMID,
+                            mainstem = LevelPathI) %>%
+      dplyr::mutate(realized_catchmentID = ifelse(realized_catchmentID %in% full_cats$FEATUREID,
+                                                  realized_catchmentID, NA)) %>%
+      left_join(select(st_drop_geometry(poi_geometry), hy_id, poi_geom_id = geom_id), 
+                by = c("NHDPlusV2_COMID" = "hy_id"))
+    
+    # sf::write_sf(lookup, nav_gpkg, lookup_table_refactor)
+  
+  list(lookup = lookup, event_table = event_table, 
+       event_geometry_table = event_geometry_table, 
+       pois_data = pois_data, poi_geometry = poi_geometry)
+  
 }
\ No newline at end of file
diff --git a/workspace/R/NHD_navigate.R b/workspace/R/NHD_navigate.R
index ec76a7dafd061e301d2212065192e9061217b3eb..644912655e3bd951430eddd7cf7fa119f7d4d7b7 100644
--- a/workspace/R/NHD_navigate.R
+++ b/workspace/R/NHD_navigate.R
@@ -1,202 +1,3 @@
-#' Creates finalized segments and routing
-#'  @param nhdDF (sf data.frame) valid data frame of NHD flowlines
-#'  @param routing_fix  (sf data.frame) any additional routing fixes
-#' 
-#' @return (sf data.frame) data.frame of segments
-segment_creation <- function(nhdDF, routing_fix = NULL){ 
-  
-  if(!"StartFlag" %in% names(nhdDF)) {
-    nhdDF$StartFlag <- ifelse(nhdDF$Hydroseq %in% nhdDF$DnHydroseq, 0, 1)
-  }
-  
-  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 (is.data.frame(routing_fix)){
-    routing_fix <- routing_fix %>%
-      rename(COMID = oldPOI, new_COMID = COMID)
-    
-    # Above we generated the network using the initial set of POIs; here we crosswalk over the old COMIDs to the new
-    nhd_fix <- nhdDF %>%
-      left_join(routing_fix %>%
-                   select(COMID, new_COMID), by = c("POI_ID" = "COMID")) %>%
-      mutate(POI_ID = ifelse(is.na(new_COMID), POI_ID, new_COMID)) %>%
-      filter(!POI_ID %in% routing_fix$COMID) %>%
-      select(-new_COMID)
-    
-    in_segs <- filter(nhd_fix, !is.na(POI_ID))
-  }
-  
-  # Dissolve flowlines to aggregated segments
-  nsegments <- filter(in_segs, !is.na(POI_ID)) %>%
-    group_by(POI_ID) %>%
-    #arrange(desc(LevelPathI), desc(Hydroseq)) %>%
-    summarize(TotalLength = sum(LENGTHKM),TotalDA = max(TotDASqKM), HW = max(StartFlag),
-              do_union = FALSE) %>%
-    #st_cast("MULTILINESTRING")  %>%
-    inner_join(st_drop_geometry(filter(in_segs, minNet == 1)) %>%
-                 select(COMID, Hydroseq, DnHydroseq), by = c("POI_ID" = "COMID"))
-  
-  # produce a short data frame for populating TO_POI for downstream segment
-  to_from <- filter(st_drop_geometry(in_segs)) %>%
-    left_join(filter(st_drop_geometry(nhdDF), !is.na(POI_ID)) %>% 
-                select(COMID, Hydroseq, POI_ID), by = c("DnHydroseq" = "Hydroseq")) %>%
-    select(COMID.x, Hydroseq, DnHydroseq, POI_ID.y) %>%
-    rename(To_POI_ID = POI_ID.y) 
-  
-  # Add To_POI_ID to dissolved segments
-  nsegments_fin <- nsegments %>% 
-    left_join(select(to_from, COMID.x, To_POI_ID), by = c("POI_ID" = "COMID.x")) %>%
-    select(POI_ID, TotalLength, TotalDA, HW, To_POI_ID) 
-  
-  return(list(diss_segs = nsegments_fin, raw_segs = in_segs))
-}
-
-### used as a cleanup step in POI workflow
-#' Moves POI Upstream or downstream if it falls on COMID
-#       of flowline with no corresponding catchment
-#'  @param POIs_wgeom (sf data.frame) POIs
-#'  @param nhdDF  (sf data.frame) valid data frame of NHD flowlines
-#' 
-#' @return (sf data.frame) data.frame of POIs with new COMID associated
-DS_poiFix <- function(POIs_wgeom, nhd){
-  nhd <- distinct(nhd)
-  POIs <- st_drop_geometry(POIs_wgeom) %>%
-    arrange(COMID) %>%
-    filter(nexus == FALSE)
-
-  # DF of downstream segment
-  tocomDF <- select(st_drop_geometry(nhd), COMID, Hydroseq, TotDASqKM,
-                    DnHydroseq, WBAREACOMI) %>%
-    inner_join(select(st_drop_geometry(nhd), COMID_ds = COMID, Hydroseq, 
-                      WBAREACOMI_down = WBAREACOMI, totda_ds = TotDASqKM), 
-               by = c("DnHydroseq" = "Hydroseq")) %>%
-    inner_join(select(st_drop_geometry(nhd), COMID_us = COMID, DnHydroseq,
-                      WBAREACOMI_up = WBAREACOMI, totda_us = TotDASqKM),
-               by = c("Hydroseq" = "DnHydroseq"))
-  
-  # Find segments with POIs where there is no corresponding catchment that are not terminal
-  unCon_fl <- filter(nhd, COMID %in% POIs$COMID, AreaSqKM == 0)# & Hydroseq != TerminalPa)
-  unCon_POIs <- filter(POIs, COMID %in% unCon_fl$COMID)
-  
-  # Get specific fixes for waterbody inlets and outlets
-  wbout <- filter(unCon_POIs, !is.na(Type_WBOut)) %>%
-    inner_join(tocomDF, by = "COMID") %>%
-    mutate(nonrefactor = ifelse(WBAREACOMI %in% WBAREACOMI_up, COMID_ds, 0),
-           new_POI = COMID_us)
-
-  wb_pois <- filter(unCon_POIs, !is.na(Type_WBIn)) %>%
-    inner_join(tocomDF, by = "COMID") %>%
-    mutate(nonrefactor = ifelse(WBAREACOMI < 0, COMID_ds, 0),
-           new_POI = COMID_us) %>%
-    rbind(wbout) %>%
-    select(-c(nexus, Hydroseq, TotDASqKM, DnHydroseq, WBAREACOMI, COMID_ds,
-              WBAREACOMI_down, totda_ds, COMID_us, WBAREACOMI_up, totda_us)) %>%
-    rename(COMID = new_POI, oldPOI = COMID)
-
-  # The rest can be resolved with drainage are ratio
-  unCon_POIs <- filter(unCon_POIs, !COMID %in% wb_pois$oldPOI)
-
-  poi_fix <- as.data.frame(do.call("rbind", lapply(unCon_POIs$COMID, movePOI_NA_DA, st_drop_geometry(nhd)))) %>%
-    inner_join(POIs, by = c("oldPOI" = "COMID")) %>%
-    inner_join(select(st_drop_geometry(nhd), COMID), by = c("oldPOI" = "COMID")) %>%
-    select(-c(AreaSqKM, DnHydroseq, nexus, TotDASqKM)) %>%
-    distinct() %>%
-    bind_rows(wb_pois)
-  
-  # Fold in new POIs with existing POIs so all the "Type" attribution will carry over
-  # using the minimum will ensure correct downstream hydrosequence gets carried over
-  poi_orig <- filter(POIs, COMID %in% poi_fix$COMID) %>%
-    bind_rows(poi_fix) %>%
-    select(-oldPOI)
-
-  list_df <- dplyr::group_by(poi_orig, COMID) |>
-    group_split()
-  
-  compact <- function(l) {
-    if(nrow(l) == 1) return(as.data.frame(l))
-    lapply(names(l), \(x) {
-      out <- unique(l[[x]][!is.na(l[[x]])])
-      if(!length(out)) NA 
-      else if(length(out) == 1) out 
-      else {
-        cat(paste("duplicate id for", unique(l$COMID),
-                  "column", x, 
-                  "values", paste(out, collapse = ", "), 
-                  "using", out[1]), file = "POI-issues.log")
-        out[1]
-      }
-    }) |> 
-      setNames(names(l)) |>
-      as.data.frame()
-  }
-  
-  poi_merged <- bind_rows(lapply(list_df, compact))
-
-  # # Combine POI information together for redundant pois  
-  # poi_merged <- poi_orig %>% 
-  #   select(-c(nexus, AreaSqKM, oldPOI, DnHydroseq, TotDASqKM)) %>%
-  #   group_by(COMID) %>%
-  #   summarise_each(funs(toString(na.omit(.)))) 
-  # is.na(poi_merged) <- poi_merged == ""
-  
-  # Join new POI COMIDs and geometry with the old Type fields
-  fin_POIs <- poi_merged %>%
-    arrange(COMID) %>%
-    bind_cols(get_node(filter(nhd, COMID %in% .$COMID) %>% arrange(COMID), position = "end")) %>%
-    st_sf() %>%
-    st_compatibalize(., POIs_wgeom)
-  
-  return (list(xWalk = poi_fix, new_POIs = fin_POIs))
-}
-
-### USED in DS_poiFix
-#' Move POIs that fall on flowlines with no catchment upstream/downstream
-#     to adjacent flowline with most similar total drainage area. Called from 
-#     DS_poi_fix function above
-#'  @param poi_fix (data.frame) POI data set of COMIDs to be changed
-#'  @param nhdDF  (sf data.frame) valid data frame of NHD flowlines
-#' 
-#' @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 <- 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(Hydroseq) %>%
-    filter(AreaSqKM > 0)
-  
-  down_segs <- unique(nhdplusTools::get_DM(nhdDF, poi_fix, sort=T))
-  downstuff <- filter(nhdDF, COMID %in% unlist(down_segs)) %>% 
-    arrange(Hydroseq)%>%
-    filter(AreaSqKM > 0)
-  
-  # combine into one dataframe, select up/downstream seg with least change in total drainage area
-  near_FL <- rbind(select(upstuff, COMID, TotDASqKM, AreaSqKM) %>% 
-                    slice(1), 
-                    select(downstuff, COMID, TotDASqKM, AreaSqKM) %>% 
-                    slice(1))
-  
-  # If 1 or other adjacent flowlines are coupled with a catchment
-  if (sum(near_FL$AreaSqKM) > 0){
-    new_POI <- near_FL[(which.min(abs(seg2fix$TotDASqKM - near_FL$TotDASqKM))),] #near_FL$COMID
-    new_POI$oldPOI <- poi_fix
-    new_POI$DnHydroseq <-seg2fix$DnHydroseq
-  } else {
-    # Remove POI if not catchment associated with flowlines upstream or downstream
-    print (poi_fix)
-    print ("US and DS flowlines also have no catchment, removing POI")
-    new_POI <- NA
-  }
-  return(new_POI)
-}
-
 ### NOTUSED? 
 #' Collaposes/merges POIs together based on drainage area ratio and data theme
 #'  @param out_gpkg (geopackage) output geopackage to write intermediate results to
@@ -507,136 +308,3 @@ split_elev <- function(in_POI_ID, split_DF, elev_diff, max_DA){
   }
   return(split_elev_DF)
 }
-
-### used when poi_move.R is sourced in POI collapse phase of workflow
-### consider calling at the end of each poi creation process?
-#'  Collapses POIs together based on criteria
-#'  @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))
-  
-}
diff --git a/workspace/R/poi_move.R b/workspace/R/poi_move.R
deleted file mode 100644
index ebfdd7a06530d5af3f1fa65318f8be33ebbed02d..0000000000000000000000000000000000000000
--- a/workspace/R/poi_move.R
+++ /dev/null
@@ -1,119 +0,0 @@
-## TODO: document this file!
-
-#  Load data
-if(collapse){
-  
-  # Move HUC12 to other POIs
-  moved_pois <- poi_move(final_POIs_prec, "Type_HUC12", poi_dar_move, 
-                         poi_distance_move) 
-  
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois$moved_points %>%
-      mutate(move_type = "huc12 to other")
-  } else {
-    final_POIs <- moved_POIs
-  }
-  
-  # Gages to confluences, terminals
-  moved_pois <- poi_move(final_POIs, "Type_Gages", poi_dar_move, 
-                         poi_distance_move, c("Type_Conf", "Type_Term"))
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois_table %>%
-      rbind(moved_pois$moved_points %>%
-              mutate(move_type = "gages to conf"))
-  } else {
-    final_POIs <- moved_POIs
-  }
-  
-  # Gages to waterbody inlets
-  moved_pois <- poi_move(final_POIs, "Type_Gages", poi_dar_move, 
-                         poi_distance_move, c("Type_WBIn", "Type_WBOut")) 
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois_table %>%
-      rbind(moved_pois$moved_points %>%
-              mutate(move_type = "gages to wbin"))
-  } else {
-    final_POIs <- moved_pois
-  }
-  
-  # Waterbody inlet to confluence
-  moved_pois <- poi_move(final_POIs, "Type_WBIn", poi_dar_move/2, 
-                         poi_distance_move*0.4, "Type_Conf")
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois_table %>%
-      rbind(moved_pois$moved_points %>%
-              mutate(move_type = "gages to term"))
-  } else {
-    final_POIs <- moved_pois
-  }
-  
-  # # Waterbody inlet to confluence
-  # moved_pois <- poi_move(final_POIs, "Type_WBOut", poi_dar_move/2, 
-  #                        poi_distance_move*0.4, "Type_WBIn")
-  # if(!is.data.frame(moved_pois)){
-  #   final_POIs <- moved_pois$final_pois
-  #   moved_pois_table <- moved_pois_table %>%
-  #     rbind(moved_pois$moved_points %>%
-  #             mutate(move_type = "gages to term"))
-  # } else {
-  #   final_POIs <- moved_pois
-  # }
-  
-  # Waterbody inlet to confluence
-  moved_pois <- poi_move(final_POIs, c("Type_WBIn", "Type_HUC12"), poi_dar_move/2, 
-                         poi_distance_move*0.4, "Type_Conf")
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois_table %>%
-      rbind(moved_pois$moved_points %>%
-              mutate(move_type = "gages to term"))
-  } else {
-    final_POIs <- moved_pois
-  }
-  
-  # NID to waterbody outlet
-  moved_pois <- poi_move(final_POIs, "Type_hilarri", poi_dar_move/2, 
-                         poi_distance_move * 0.4, c("Type_WBOut", "Type_TE"))
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois_table %>%
-      rbind(moved_pois$moved_points %>%
-              mutate(move_type = "nid to wb_out"))
-  } else {
-    final_POIs <- moved_pois
-  }
-  
-  # NID to waterbody outlet
-  moved_pois <- poi_move(final_POIs, "Type_DA", poi_dar_move, 
-                         poi_distance_move)
-  if(!is.data.frame(moved_pois)){
-    final_POIs <- moved_pois$final_pois
-    moved_pois_table <- moved_pois_table %>%
-      rbind(moved_pois$moved_points %>%
-              mutate(move_type = "nid to wb_out"))
-  } else {
-    final_POIs <- moved_pois
-  }
-  
-  if("Type_elev" %in% names(final_POIs)){
-    # NID to waterbody outlet
-    moved_pois <- poi_move(final_POIs, "Type_elev", poi_dar_move, 
-                           poi_distance_move)
-    if(!is.data.frame(moved_pois)){
-      final_POIs <- moved_pois$final_pois
-      moved_pois_table <- moved_pois_table %>%
-        rbind(moved_pois$moved_points %>%
-                mutate(move_type = "nid to wb_out"))
-    } else {
-      final_POIs <- moved_pois
-    }
-  }
-
-  
-  write_sf(final_POIs, nav_gpkg, pois_all_layer)
-  write_sf(moved_pois_table, temp_gpkg, "pois_collapsed")
-} 
\ No newline at end of file
diff --git a/workspace/_targets/02_POI_creation_targets.R b/workspace/_targets/02_POI_creation_targets.R
index f6c19d43be425ce89ab4bab571b2f86ca49947a4..b66c4956c319aa800204c92554e08417e3d2af96 100644
--- a/workspace/_targets/02_POI_creation_targets.R
+++ b/workspace/_targets/02_POI_creation_targets.R
@@ -12,6 +12,7 @@ source("R/config.R")
 source("R/user_vars.R")
 source("R/utils.R")
 source("R/02_POI_creation_functions.R")
+source("R/poi_move.R")
 
 prep_path <- ".targets_stores/01_prep/objects/"
 
@@ -27,6 +28,8 @@ list(tar_target(data_paths_file, "cache/data_paths.json", format = "file"),
                 pattern = map(nav_gpkg), deployment = "worker"),
      tar_target(all_nhdplus_attributes, 
                 sf::st_drop_geometry(sf::read_sf(data_paths$nhdplus_gdb, "NHDFlowline_Network"))),
+     tar_target(full_cat_file, data_paths$fullcats_table, format = "file"),
+     tar_target(full_cat_table, readRDS(full_cat_file)),
      
      ### huc12 pois
      tar_target(huc12_poi, create_hu12_pois(read_sf(data_paths$hu12_points_path, "hu_points"),
@@ -148,5 +151,23 @@ list(tar_target(data_paths_file, "cache/data_paths.json", format = "file"),
                                                                 updated_flowline_confluence,
                                                                 all_nhdplus_attributes,
                                                                 "Travel"),
-                pattern = map(elevation_break_pois, updated_flowline_confluence), deployment = "worker")
+                pattern = map(elevation_break_pois, updated_flowline_confluence), deployment = "worker"),
+     
+     tar_target(final_pois, create_final_pois(time_of_travel_pois$tmp_POIs,
+                                              updated_flowline_confluence),
+                pattern = map(time_of_travel_pois, updated_flowline_confluence), deployment = "worker"),
+     
+     tar_target(draft_segments, create_draft_segments(final_pois$final_POIs, 
+                                                      updated_flowline_confluence,
+                                                      final_pois$xwalk),
+                pattern = map(final_pois, updated_flowline_confluence), deployment = "worker"),
+     
+     tar_target(collapsed_pois, collapse_pois(final_pois$final_POIs, poi_dar_move, poi_distance_move,
+                                              updated_flowline_confluence), 
+                pattern = map(final_pois, updated_flowline_confluence), deployment = "worker"),
+     
+     tar_target(poi_lookup, 
+                create_poi_lookup(collapsed_pois$final_POIs, wb_inlet_pois$events, 
+                                  full_cat_table, updated_flowline_confluence, collapsed_pois$pois_collapsed),
+                pattern = map(collapsed_pois, wb_inlet_pois, updated_flowline_confluence))
   )
\ No newline at end of file
diff --git a/workspace/workflow_runner.R b/workspace/workflow_runner.R
index 090e00a77e60da7468df00fdd368d1f4a514b1fb..9fd575782d61558c8867925b7bdcc82afc7485ed 100644
--- a/workspace/workflow_runner.R
+++ b/workspace/workflow_runner.R
@@ -38,9 +38,11 @@ if(FALSE) { # this won't run if you just bang through this file
   tar_make(callr_function = NULL)
 }
 
+workers <- 8
+
 # run branches for a given target in parallel if you have enough memory
 # note this will only work for targets with 'deployment = "worker"'
-tar_make_future(rpu_vpu_out_list, workers = 8)
+tar_make_future(rpu_vpu_out_list, workers = workers)
 tar_make(rpu_vpu_out)
 
 # make sure to run all too!
@@ -48,19 +50,22 @@ tar_make()
 
 Sys.setenv(TAR_PROJECT = "02_POI_creation")
 
-tar_make_future(huc12_poi, workers = 8)
-tar_make_future(gage_pois, workers = 8)
-tar_make_future(te_pois, workers = 8)
-tar_make_future(resops_pois, workers = 8)
-tar_make_future(hilarri_pois, workers = 8)
-tar_make_future(wb_outlet_pois, workers = 8)
-tar_make_future(write_wb_flowline_mod, workers = 8)
-tar_make_future(ar_event_pois, workers = 8)
-tar_make_future(terminal_pois, workers = 8)
-tar_make_future(updated_flowline_confluence, workers = 8)
-tar_make_future(wb_inlet_pois, workers = 8)
-tar_make_future(nid_pois, workers = 8)
-tar_make_future(headwater_pois, workers = 8)
-tar_make_future(elevation_break_pois, workers = 8)
-tar_make_future(time_of_travel_pois, workers = 8)
-
+tar_make_future(huc12_poi, workers = workers)
+tar_make_future(gage_pois, workers = workers)
+tar_make_future(te_pois, workers = workers)
+tar_make_future(resops_pois, workers = workers)
+tar_make_future(hilarri_pois, workers = workers)
+tar_make_future(wb_outlet_pois, workers = workers)
+tar_make_future(write_wb_flowline_mod, workers = workers)
+tar_make_future(ar_event_pois, workers = workers)
+tar_make_future(terminal_pois, workers = workers)
+tar_make_future(updated_flowline_confluence, workers = workers)
+tar_make_future(wb_inlet_pois, workers = workers)
+tar_make_future(nid_pois, workers = workers)
+tar_make_future(headwater_pois, workers = workers)
+tar_make_future(elevation_break_pois, workers = workers)
+tar_make_future(time_of_travel_pois, workers = workers)
+tar_make_future(final_pois, workers = workers)
+tar_make_future(draft_segments, workers = workers)
+tar_make_future(collapsed_pois, workers = workers)
+tar_make_future(poi_lookup, workers = workers)