###############################
##Code modified from Fletcher and Fortin 2019, Chapter 9
##Textbook - Spatial Ecology and Conservation Modeling
###############################

#gdistance pdf: https://mran.microsoft.com/snapshot/2017-02-04/web/packages/gdistance/vignettes/gdistance1.pdf

#load packages
library(raster)           
## Loading required package: sp
library(gdistance)        #for calculating connectivity metrics
## Loading required package: igraph
## 
## Attaching package: 'igraph'
## The following object is masked from 'package:raster':
## 
##     union
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
## Loading required package: Matrix
## 
## Attaching package: 'gdistance'
## The following object is masked from 'package:igraph':
## 
##     normalize
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✓ ggplot2 3.3.5     ✓ purrr   0.3.4
## ✓ tibble  3.1.4     ✓ dplyr   1.0.7
## ✓ tidyr   1.1.3     ✓ stringr 1.4.0
## ✓ readr   2.0.1     ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::as_data_frame() masks tibble::as_data_frame(), igraph::as_data_frame()
## x purrr::compose()       masks igraph::compose()
## x tidyr::crossing()      masks igraph::crossing()
## x tidyr::expand()        masks Matrix::expand()
## x tidyr::extract()       masks raster::extract()
## x dplyr::filter()        masks stats::filter()
## x dplyr::groups()        masks igraph::groups()
## x dplyr::lag()           masks stats::lag()
## x tidyr::pack()          masks Matrix::pack()
## x dplyr::select()        masks raster::select()
## x purrr::simplify()      masks igraph::simplify()
## x tidyr::unpack()        masks Matrix::unpack()
library(sf)
## Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1
library(mapview)

#pull in RVA NLCD
lc<-raster("GrRVA_NLCD_2019.tif")

#label projection for later use
crs.land <- projection(lc)

#Richmond City Parks in need of connections
parks <- st_read("Parks.shp")
## Reading layer `Parks' from data source 
##   `/Users/joshuasementelli/Downloads/Connectivity/Parks.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 169 features and 13 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 11748520 ymin: 3694416 xmax: 11805200 ymax: 3744511
## Projected CRS: NAD83 / Virginia South (ftUS)
parks<-st_transform(parks, crs.land)

#look at them
mapview(parks)
#identify a few parks to use for assessing landscape connectivity
#I selected Hugeunot FW, Larus park, Powhite park, and PP wetlands, 
#b/c I am most familiar with these, but you can choose 
#different ones if you like.  
#I found OBJECTID by clicking on each park in mapview

parks<-filter(parks, OBJECTID == 186 | OBJECTID == 245 | 
                OBJECTID == 169 | OBJECTID == 241)

#crop NLCD to match this smaller extent where parks are located
lc_crop<-crop(lc, parks)

#identify the centroid of each park
park_cent <- st_centroid(parks, byid=T)
## Warning in st_centroid.sf(parks, byid = T): st_centroid assumes attributes are
## constant over geometries of x
#plot parks and centroids
plot(lc_crop)

plot(park_cent, add=T, color = "black", pch=20)
## Warning in plot.sf(park_cent, add = T, color = "black", pch = 20): ignoring all
## but the first attribute

#reclassify NLCD as resistance values:
lc_crop<-as.factor(lc_crop)

#Consider the resistance values (1-4, 1=low resistance and 4=high resistance) 
#for each of the following cover types 
#I was considering white tailed deer and/or red fox which I see in my 
#neighborhood. 
#you can consider other species of interest and change these values. 
#typically this step would require a literature review so that it can be 
#based on empirical data and expert opinion

#water = 4
#urban_low = 2
#urban_medLow = 2
#urban_Med = 3
#urban_high = 4
#barren = 2
#forest_dec = 1
#forest_eg = 1
#forest_mix = 1
#shrub = 1
#grass = 2
#pasture = 2
#crops = 2
#woody wetland = 1
#herbaceous wetland = 2

#create reclassification matrix based on above
reclass <- c(rep(4,1), rep(2,2), rep(3,1), rep(4,1), 
             rep(2,1) ,rep(1,4), rep(2,3), rep(1,1), rep(2,1))

reclass.mat <- cbind(levels(lc_crop)[[1]], reclass)
#we can use levels with raster package instead of unique for the terra package

#convert to factor and reclassify (these are different for raster than terra)
lc_crop<-as.factor(lc_crop)
resist <- reclassify(lc_crop, reclass.mat)

#plot resistance raster
plot(resist)
plot(park_cent, add=T, pch=20, color="black")
## Warning in plot.sf(park_cent, add = T, pch = 20, color = "black"): ignoring all
## but the first attribute

#create a conductance transition layer (inverse of resistance data) 
#as mean of conductance
land_cond <- transition(1/resist, transitionFunction=mean, 8)

#also make a correction for the transition layer to account for diagonal 
#connections from 8 neghborhood rule
#type=c for lcps; type = r for circuit - results same for this example
land_cond <- geoCorrection(land_cond, type="c", multpl=F)
?geoCorrection
#look at it by transforming the transition matrix to a raster
plot(raster(land_cond))#represents conductance

#geographic (Euclidean) distance matrix - as the crow flies
geo.dist <- pointDistance(park_cent, lonlat=FALSE)
?pointDistance
geo.dist <- as.dist(geo.dist)
?as.dist
## Help on topic 'as.dist' was found in the following packages:
## 
##   Package               Library
##   proxy                 /Library/Frameworks/R.framework/Versions/4.0/Resources/library
##   stats                 /Library/Frameworks/R.framework/Versions/4.0/Resources/library
## 
## 
## Using the first match ...
?pointDistance
#convert park centroids to sp
park_cent_sp<-as_Spatial(park_cent)
#least-cost distance matrix
lc.dist <- costDistance(land_cond, park_cent_sp)
?costDistance
#commute distance matrix calculates the resistance distance (circuit theory)
#can take a long time with larger rasters
circuit.dist <- commuteDistance(land_cond, park_cent_sp)

#randomized shortest-paths distance matrix 
#   theta is the degree from which the path randomly deviates from the shortest path
##0 < theta < 20
#can take a long time on larger rasters
rSP.dist_t0001 <- rSPDistance(land_cond, 
                              from=park_cent_sp, 
                              to=park_cent_sp, 
                              theta=0.0001)
?rSPDistance
#inspect
geo.dist
##          1        2        3
## 2 4390.036                  
## 3 2942.696 2854.240         
## 4 4164.740 2411.543 4323.109
lc.dist
##          1        2        3
## 2 5844.601                  
## 3 3892.082 3298.356         
## 4 5843.113 3048.600 5824.163
circuit.dist
##          1        2        3
## 2 194237.6                  
## 3 169481.5 182767.0         
## 4 178508.2 154758.5 187499.1
rSP.dist_t0001
##          [,1]     [,2]     [,3]     [,4]
## [1,]    0.000 9652.480 6247.312 9273.446
## [2,] 9652.480    0.000 5767.176 4973.674
## [3,] 6247.312 5767.176    0.000 9348.709
## [4,] 9273.446 4973.674 9348.709    0.000
#take lower triangle of rSP.dist_t0001
rSP.dist_t0001.tri <- rSP.dist_t0001
rSP.dist_t0001.tri[upper.tri(rSP.dist_t0001.tri, diag=TRUE)] <- NA

#inspect
rSP.dist_t0001.tri
##          [,1]     [,2]     [,3] [,4]
## [1,]       NA       NA       NA   NA
## [2,] 9652.480       NA       NA   NA
## [3,] 6247.312 5767.176       NA   NA
## [4,] 9273.446 4973.674 9348.709   NA
#make data frame of distances
all.dist <- data.frame(Euclidean=as.vector(geo.dist),
                       lcd=as.vector(lc.dist),
                       circuit=as.vector(circuit.dist),
                       rSP=na.omit(as.vector(rSP.dist_t0001.tri)))

#correlation
pairs(all.dist[,1:4], pch = 19, lower.panel = NULL)

cor<-round(cor(all.dist),3)

library(corrplot)
## corrplot 0.90 loaded
corrplot(cor, method="number", type = "lower")

#are these measures correlated?  Do relationships appear linear?
#any other observations?

##There does seem to be some correlation between the metrics calculated, especially between euclidean and lcd.

#now that we have quantified these metrics, now let's map them:

#First Least Cost Path:

#map shortest path between each park, start with path between park 1 and park 2
parks_lcp12 <- shortestPath(land_cond, 
                           park_cent_sp@coords[1,], park_cent_sp@coords[2,],
                           output = "SpatialLines")

#if you want to get all paths from one park to the others, input range of values of the goal location
parks_lcp1 <- shortestPath(land_cond, 
                            park_cent_sp@coords[1,], park_cent_sp@coords[1:4,],
                            output = "SpatialLines")

parks_lcp2 <- shortestPath(land_cond,
                            park_cent_sp@coords[2,], park_cent_sp@coords[1:4,],
                            output = "SpatialLines")

parks_lcp3 <- shortestPath(land_cond,
                            park_cent_sp@coords[3,], park_cent_sp@coords[1:4,],
                            output = "SpatialLines")

parks_lcp4 <- shortestPath(land_cond,
                            park_cent_sp@coords[2,], park_cent_sp@coords[4,],
                            output = "SpatialLines")

#plot these shortest paths
plot(resist, axes = F)
plot(park_cent_sp, pch = 20, add = T)
lines(parks_lcp1, col = "red")
lines(parks_lcp2, col = "red")
lines(parks_lcp3, col = "red")
lines(parks_lcp4, col = "red")

#notice that some of the lines are not lying right on top of each other...
#why do you think that might be?

##Lines are not exactly overlaying each because each pathway from either park 1 to park 2 or vice versa will not always have the some obstacles throughout the pathway. This wull cause variation in the shortest pathway lines.

#No Least Cost Corridors:

#mapping least cost corridors are better than paths (single line) which may not be reliable/used.
#this requires a few steps:
#first is to create the cumulative cost/resistance from each location
acc.cost1 <- accCost(land_cond, park_cent_sp@coords[1,])
acc.cost2 <- accCost(land_cond, park_cent_sp@coords[2,])
acc.cost3 <- accCost(land_cond, park_cent_sp@coords[3,])
acc.cost4 <- accCost(land_cond, park_cent_sp@coords[4,])

plot(acc.cost2)

#overlay the costs between two parks by adding the two layers and 
#clip new layer based on specific quantile of cost 
#(increasing the quantile will increase the width)
leastcost_corridor <- overlay(acc.cost1, acc.cost2, fun = function
                              (x, y){return (x + y)})

plot(leastcost_corridor)

#get lower 10% quantile of accumulated cost/resistance
quantile10 <- quantile(leastcost_corridor, probs = 0.10, na.rm = TRUE)
#create a blank raster that is the same size as leastcost_corridor
leastcost_corridor10 <- leastcost_corridor
values(leastcost_corridor10) <- NA

#subset only the area with 10% quatile and give it a value of 1
leastcost_corridor10[leastcost_corridor < quantile10] <- 1

#plot it, add points, and LCP line from above
plot(leastcost_corridor10,legend = F,axes = F)
points(park_cent_sp, col = "grey30")
lines(parks_lcp12, col = "red")

# we can now look at land cover along this predicted path for conservation planning
# using the extract function in raster package

#identify land-cover along the lcp
lcp.land <- raster::extract(lc_crop, parks_lcp12)
table(lcp.land)
## lcp.land
## 21 22 23 24 31 41 42 43 90 
## 39  7  7  1  2 29 11 92 18
#identify land-cover along the least-cost corridor
corridor.land <- crop(lc_crop, leastcost_corridor10)
corridor.land <- mask(corridor.land, leastcost_corridor10)
plot(corridor.land, axes = F, legend = F)

## Warning in plot.window(...): "legend" is not a graphical parameter
## Warning in plot.xy(xy, type, ...): "legend" is not a graphical parameter
## Warning in title(...): "legend" is not a graphical parameter
## Warning in graphics::rasterImage(z, bb[1], bb[3], bb[2], bb[4], interpolate =
## interpolate, : "legend" is not a graphical parameter

table(as.vector(corridor.land))
## 
##  21  22  23  24  31  41  42  43  52  81  90  95 
## 941 220 129  17  15 337  90 765   1   4 250   1
#what are the most common land-cover types in the least-cost path and least-cost corridor?
#you can repeat this for the other set of two parks if you like
 ##Least cost path: mixed forest, developed land, and decidous forest
##Least-cost corridor: Mixed forest, Woody wetland, developed land, deciduous forest 

#lastly, we can model flow using randomized shortest-path analysis
#must alter the tuning parameter - theta -  to interpret this model

#when theta = 0, we are mapping a biased random walk
#movement is diffuse with no hard boundaries
passage.map_t0 <- passage(land_cond,
                          origin = park_cent_sp@coords[1,],
                          goal = park_cent_sp@coords[2,], theta = 0)

#alter theta to converge on a lcp
#as theta increases, the prob of passage become more well-deinfed andincrease around the lcp and lc corridor
passage.map_t0001 <- passage(land_cond,
                             origin = park_cent_sp@coords[1,],
                             goal = park_cent_sp@coords[2,], theta = 0.0001)

passage.map_t001 <- passage(land_cond,
                            origin = park_cent_sp@coords[1,],
                            goal = park_cent_sp@coords[2,], theta = 0.001)

passage.map_t002 <- passage(land_cond,
                            origin = park_cent_sp@coords[1,],
                            goal = park_cent_sp@coords[2,], theta = 0.05)


plot(passage.map_t0, axes=F, legend=F)

plot(passage.map_t0001, axes=F, legend=F)

plot(passage.map_t001, axes=F, legend=F)

plot(passage.map_t002, axes=F, legend=F)

#try different values of theta and see which one you think is best - explain
##The final plot displayed above with a theta parameter value of .05 I think bests fits the least cost path. With this value, pathways align where resistance is at the lowest.
#what additional data is needed to better answer the question about connectivity between these parks for wildlife?
##Predators present, slope of landscape could be factors that help answer questions on connectivity for wildlife.
#Do you have any other observations or comments to make about this exercise