josephlewis / leastcostpath

leastcostpath: Modelling Pathways and Movement Potential Within a Landscape
60 stars 7 forks source link

Multiple Start Points for create_accum_cost #22

Closed gcperk closed 1 year ago

gcperk commented 1 year ago

Hi @josephlewis , Great work on the package update/ incorporation of terra for the create_accum_cost(). This is a much faster implementation!

I am currently using your create_slope_cs() and create_accum_cost() functiosn to build a cost surface based on slope (tobler offpath) and road speeds combined. I modified your functions to incorporate this aspect:(https://github.com/bcgov/PEMsamplr/blob/main/R/prep_cost_layer_LCP.R)

For my next stage of testing I want to incorporate multiple start locations in the create_accum_cost(). I noted in the coding you say it only reads the first point/row. My colleague and I have tested a few variations in this but it is failing.

image

Is this correct and only single start points are able to be used to create the function? If so perhaps this could be an enhancement down the track?

Thanks again for the great coding!

josephlewis commented 1 year ago

Hi @gcperk

Yes, it is correct that it only takes the first row. But I can modify this to work row-by-row and return a list/SpatRaster with multiple layers

This error is normally caused when your point is outside the extent of your conductanceMatrix (your costprep).

library(leastcostpath)
library(terra)

r <- terra::rast(system.file("extdata/SICILY_1000m.tif", package="leastcostpath"))

slope_cs <- create_slope_cs(x = r, cost_function = "tobler", neighbours = 4)

loc <- sf::st_sf(geometry = sf::st_sfc(sf::st_point(c(839769, 4199443)),crs = terra::crs(r)))
loc1 <- sf::st_sf(geometry = sf::st_sfc(sf::st_point(c(1013340, 4337459)),crs = terra::crs(r)))

cc <- create_accum_cost(x = slope_cs, origin = loc, rescale = TRUE)
cc1 <- create_accum_cost(x = slope_cs, origin = loc1, rescale = TRUE)

In regards to your modification of the conductanceMatrix for road speeds you could do use the _updatevalues function instead:

slope_cs <- create_slope_cs(x = r, cost_function = "tobler", neighbours = 4)

locs <- sf::st_sf(geometry = sf::st_sfc(
  sf::st_point(c(960745, 4166836)),
  crs = terra::crs(r)))

locs <- sf::st_buffer(x = locs, dist = 25000)

# all cells that coincide with the sf object are updated to whatever you provide in the function. 
# e.g. here I replace all values that coincide with the sf with a value of 30
slope_cs4 <- update_values(x = slope_cs, sf = locs, 
                           FUN = function(j) { replace(x = j, values = 30)})

plot(slope_cs4)

# for example here we can see all connections to cell 51012 are given a value of 30.
# i.e. the conductance to this cell from all neighbouring cells has a value of 30
slope_cs4$conductanceMatrix[,51012][slope_cs4$conductanceMatrix[,51012] != 0]

Hope that helps :) Let me know if you think the problem is somewhere else.

I'll try and update the creat_accum_cost ASAP

josephlewis commented 1 year ago

Moving forward I will also work on updating the check_locations function to be used within all functions that require a location to be specified. That way, it should automatically flag up any issues with locations being outside extent, not reachable etc.

gcperk commented 1 year ago

Thanks @josephlewis - I will look into your suggestions for the roads.

My colleague @kdaust made a test version of the multiple start points here: create_accum_cost_multistart()

Also would you be open to making some of your internal package functions open (get_coordinates , neighbourhood ,calculate_distance). This way I can reference (and acknowledge!) your package directly.

josephlewis commented 1 year ago

Hi @gcperk and @kdaust,

Thanks for the test version and for flagging this addition! When initially creating the function, I didn't know that igraph::distances allowed multiple locations.

I've updated create_accum_cost to allow for multiple origin points on the dev version. Rather than assuming the function applied to the multiple accumulated cost surfaces (e.g. by assuming people want to get the minimum value for each cell across multiple layers), I've added a FUN argument. This FUN argument summaries the values for each cell across the layers.

library(devtools)
install_github("josephlewis/leastcostpath@dev")

Let me know if this works for you and I'll push to main.

Thanks, Joe!

gcperk commented 1 year ago

Hi @josephlewis - I just tested it and it is working well. Thanks for making those additions and updating the internal functions. Cheers, Gen