Skip to content

Commit e766113

Browse files
author
Matthew Talluto
committed
Prelim work on reach topology
1 parent 3b59574 commit e766113

File tree

3 files changed

+47
-18
lines changed

3 files changed

+47
-18
lines changed

R/topology.r

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ reach_topology = function(x, Tp, stream) {
2525
if(!all.equal(rids, 1:length(rids)))
2626
stop("ReachIDs not in strict ascending order, they must be renumbered")
2727

28-
adj = lapplfun(reaches, function(r) .reach_upstream(ws, r))
28+
adj = lapplfun(rids, .upstream_r, stream = stream, Tp = Tp)
2929
adj = do.call(rbind, adj)
3030
stop("check the below; I think columns are reversed")
3131
adjspMat = Matrix::sparseMatrix(adjMat[,1], adjMat[,2], dims=rep(max(ws$data$reachID), 2),
@@ -34,30 +34,59 @@ reach_topology = function(x, Tp, stream) {
3434

3535
}
3636

37-
#' Find all reaches directly upstream from a given reach
37+
#' Find all reaches directly upstream from a given reach using a pixel topology
38+
#' @param stream A stream raster (as produced by [delineate()]) with reachIDs as the values
39+
#' @param Tp Pixel topology for the stream raster
40+
#' @param rid The focal reach ID
41+
#' @return A named2-column matrix, 'to' is the downstream reach (i.e., rid) and
42+
#' 'from' contains ids of the reach(es) upstream of rid, or NULL if there are none
3843
#' @keywords internal
39-
.reach_upstream <- function(Tp, rid) {
40-
41-
stop("update")
42-
ids <- which(ws$data$reachID == rch)
43-
reachAdj <- ws$adjacency[ids,ids, drop = FALSE]
44-
mostUpstream <- ids[which(Matrix::rowSums(reachAdj) == 0)]
45-
adjMatUp <- as.matrix(ws$adjacency[mostUpstream,])
46-
upRch <- which(adjMatUp == 1)
47-
if(length(upRch) > 0) {
48-
upRch <- ws$data$reachID[upRch]
49-
return(cbind(rch, upRch))
50-
} else return(NULL)
44+
.upstream_r = function(rid, stream, Tp) {
45+
pids = which(values(stream) == rid)
46+
Tp_r = Tp[pids, pids, drop=FALSE]
47+
r_top = .headwater(Tp_r)
48+
r_nb = .upstream(Tp, r_top)
49+
if(length(r_nb) > 0) {
50+
from_ids = stream[r_nb]
51+
res = cbind(to = rid, from = from_ids)
52+
} else {
53+
res = NULL
54+
}
55+
res
56+
}
57+
58+
#' @keywords internal
59+
.headwater = function(Tx) {
60+
## check for rowsums as well because we exclude nodes that are connected to nothing
61+
which(colSums(Tx) == 0 & rowSums(Tx) != 0)
5162
}
5263

64+
#' Simple topological functions
65+
#' @details upstream/downstream take a single node as input, and return the up- or downstream node.
66+
#' Outlets/headwaters analyzes the entire toplogy and finds nodes that have no downstream or upstream neighbours.
67+
#' @param Tx A (pixel or reach) topology
68+
#' @param i,j Focal node
69+
#' @return The id (corresponding to dims of Tx) of the desired node(s)
70+
#' @keywords internal
71+
.upstream = function(Tx, j) {
72+
which(Tx[,j] != 0)
73+
}
5374

75+
#' @keywords internal
76+
.downstream = function(Tx, i) {
77+
which(Tx[,j] != 0)
78+
}
5479

5580

56-
#' Buid a topology for each pixel in a delineated stream
81+
#' Buid a topology for a delineated stream
5782
#' @param x A [raster::stack], such as one created by [delineate()], or specify layers separately with `drain` and `stream`.
5883
#' @param drainage Optional, ignored if `x` is provided; a drainage direction raster
5984
#' @param stream Optional, ignored if `x` is provided; a delineated stream raster, all non-stream cells must be `NA`
60-
#' @return A [Matrix::sparseMatrix] giving the pixel topology
85+
#' @details The topology is a square matrix showing immediate adjacency between pixels/reaches. Each row/column
86+
#' in the topology is a single pixel/reach. Zero entries indicate no adjacency between two nodes. A non-zero entry
87+
#' for row `i` column `j` indicates that `i` is upstream of `j`. The value in the entry is the length of the
88+
#' upstream pixel/reach.
89+
#' @return A [Matrix::sparseMatrix] giving the pixel or reach topology
6190
#' @export
6291
pixel_topology = function(x, drainage, stream) {
6392
if(!requireNamespace("Matrix"))

R/zzz.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Sys.setenv("GRASS_VERBOSE"=0)
33
rgrass7::use_sp()
44

5-
if(requireNamespace("parallel") & !grepl("[Ww]indows", Sys.info()['sysname'])) {
5+
if(is.null(getOption("mc.cores")) && !grepl("[Ww]indows", Sys.info()['sysname'])) {
66
message("For faster performance of some fucntions on a machine with lots of RAM, you can set")
77
message("options(mc.cores = parallel::detectCores())")
88
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Before installing this package, you should install [GRASS GIS](https://grass.osg
1212

1313
**Mac**: `watershed` can auto-detect [grass binary](http://grassmac.wikidot.com) installations (which are usually installed in `/Applications/`). Command-line installations may also work; try following the linux instructions.
1414

15-
**Linux/Unix**: Install grass however you like. For auto-detection to work, make sure the grass binary (`grass74`, `grass76`, `grass78`) is in your `$PATH` and visible from within R; try `system2('grass76', args = c("--config", "path"))` to see if this is working, it should output the location of your grass installation. If you want a different version of grass, you can alias `grass78` to whatever binary you like, or see **Changing the default grass* below.
15+
**Linux/Unix**: Install grass however you like. For auto-detection to work, make sure the grass binary (`grass74`, `grass76`, `grass78`) is in your `$PATH` and visible from within R; try, e.g., `system2('grass76', args = c("--config", "path"))` to see if this is working, it should output the location of your grass installation. If you want a different version of grass, you can alias `grass78` to whatever binary you like, or see **Changing the default grass* below.
1616

1717
## Installing `watershed`.
1818

0 commit comments

Comments
 (0)