---
title: "Non-dendritic networks"
author: "dblodgett@usgs.gov"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Non-dendritic networks}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
library(hydroloom)
library(dplyr)

local <- (Sys.getenv("BUILD_VIGNETTES") == "TRUE")

knitr::opts_chunk$set(
  collapse = TRUE,
  warning = FALSE,
  comment = "#>",
  fig.width = 6,
  fig.height = 6,
  fig.align = "center",
  eval = local
)

oldoption <- options(scipen = 9999)
```

# Introduction

`vignette("hydroloom")` and `vignette("advanced_network")` talks about the basics of network topology representation and attributes that build on a strictly dendritic network. This vignette expands those topics by describing `hydroloom` functionality that supports non-dendritic networks.

The term "non-dendritic" refers to any network that does not follow a dendritic flow pattern. Typically, this is where one or more flowlines divert from a primary flow path. However, non-dendritic can also refer to endorheic basins that are nested within an otherwise dendritic basin. This article pertains to the former, "non-dendritic networks" which contain diverted flowlines.

The two terms: "diversion" and "divergence" are used in similar contexts but have distinct meaning. A **diversion is a diverted flowline** (waterbody) where as a **divergence is where the network diverges**. "Diversion" is often associated with anthropogenic features but a diversion can also be a naturally occurring diverted flow. 

# Non-dendritic topology attributes.

Non-dendritic networks represent downstream diverted flow where one path is primary and all others are thought to be secondary. The following attributes are supported by `hydroloom` to help track and work with this primary and secondary downstream categorization.

## fromnode and tonode

The attributes `fromnode` and `tonode` are used to store a flow network as a edge node topology where every network feature has one and only one node upstream and one and only one node downstream. Nodes are useful if converting a flow network to a graph and are useful in many analysis contexts as there is a single identifier for a confluence or divergence.

## divergence

The `divergence` attribute indicates if a downstream connection is primary (1) or secondary (2). If 0, a connection is not downstream of a divergence. This attribute is useful as it facilitates following a flow network in the "downstream mainstem" direction at every divergence.

## return divergence

The `return divergence` attribute indicates that one or more of the features upstream of a given feature originates from a divergence.  If 0, the upstream features are not part of a diversion. If 1, one or more of the upstream features is part of a diversion.

## stream calculator

The `stream calculator` attribute is part of the modified Strahler stream order as implemented in the NHDPlus data model. It indicates if a given feature is part of the downstream mainstem dendritic network or is part of a diverted path. If 0, the path is part of a diversion. Otherwise `stream calculator` will be equal to stream order. When generating Strahler stream order, if stream calculator is 0 for a given feature, that feature is not considered for incrementing downstream stream order.

## summary

As a system, `stream calculator`, `divergence` and `return divergence` support network navigation and processing in the context of diverted paths.

1. A feature at the top of a diversion will have `divergence` set to 1.
1. All features that are part of a diversion that has not yet recombined with a main path, will have `stream calculator` set to 0.
1. A feature that is just downstream of where a diversion recombines with a main path will have `return divergence` set to 1.

## Bringing it all together

The example below shows how we can recreate the non-dendritic attributes and use them in practice.

We'll start with the small sample watershed that's included in `hydroloom` and select only the attributes required to recreate the non-dendritic network.

```{r}
x <- sf::read_sf(system.file("extdata/new_hope.gpkg",
  package = "hydroloom"))

# First we select only an id, a name, and a feature type.
flow_net <- x |>
  select(COMID, GNIS_ID, FTYPE) |>
  sf::st_transform(5070)

# Now we convert the geometric network to an attribute topology
# and convert that to a node topology and join our attributes back
flow_net <- flow_net |>
  make_attribute_topology(min_distance = 5) |>
  hydroloom::make_node_topology(add_div = TRUE) |>
  left_join(sf::st_drop_geometry(flow_net), by = "COMID")

# We only have one outlet so it doesn't matter if it is coastal
# or inland but we have to provide it.
outlets <- filter(flow_net, !tonode %in% fromnode)

# We have these feature types. A larger dataset might include
# things like canals which would not be considered  "major"
unique(flow_net$FTYPE)

# now we run the add_divergence, add_toids, and add_streamorder
flow_net <- add_divergence(flow_net,
  coastal_outlet_ids = c(),
  inland_outlet_ids = outlets$COMID,
  name_attr = "GNIS_ID",
  type_attr = "FTYPE",
  major_types = unique(flow_net$FTYPE)) |>
  add_toids() |>
  add_streamorder() |>
  add_return_divergence()

# Make sure we reproduce what came from our source NHDPlus data.
sum(flow_net$divergence == 2)
sum(x$Divergence == 2)
all(flow_net$divergence == x$Divergence)
sum(flow_net$return_divergence == x$RtnDiv)

names(flow_net)
```
With the above code, we removed all attributes other than an ID, a name and a feature type and recreated both a dendritic (toid) and non-dendritic (fromnode tonode) topology. We added `divergence` attribute, `stream_order`, `stream_calculator`, and `return_divergence` attributes.
