Search code examples
rgeospatialterra

Can we use spatialEco::hsp function in parallel with terra::app?


I'm trying to calculate the hierarchical slope position in parallel:

library(terra)
library(spatialEco)

r <- rast()
result <- (r, hsp, core=12)

I get the following error:

Error in fin(v, ...): v must be a terra SparRaster class object

Is there a way to parallelize any {spatialEco} functions?


Solution

  • The function spatEco::hsp was written to deal with raster*object, so you have to try with clusterR if you want to parallelize it. However, since the function rely on focal operation, I don't know if would be possible to parallelize it. To gain some computational time you can use a modified version of hsp, written to use spatRast:

    terra_hsp <-
      function (x,
                min.scale = 3,
                max.scale = 27,
                inc = 4,
                win = "rectangle",
                normalize = FALSE)
      {
        scales = rev(seq(from = min.scale, to = max.scale, by = inc))
        for (s in scales) {
          if (win == "circle") {
            if (min.scale < terra::res(x)[1] * 2)
              stop("Minimum resolution is too small for a circular window")
            m <- terra::focalMat(x, s, type = c("circle"))
            m[m > 0] <- 1
          }
          else {
            m <- matrix(1, nrow = s, ncol = s)
          }
          message("Calculating scale:", s, "\n")
          scale.r <- x - terra::focal(x, w = m, fun = mean)
          if (s == max(scales)) {
            scale.r.norm <- 100 * ((
              scale.r - as.numeric(terra::global(
                scale.r,
                stat = "mean", na.rm =
                  T
              )) / as.numeric(terra::global(
                scale.r, stat = "sd", na.rm = T
              ))
            ))
          }
          else {
            scale.r.norm <- scale.r.norm + 100 * ((
              scale.r -
                as.numeric(terra::global(
                  scale.r, stat = "mean", na.rm = T
                )) / as.numeric(terra::global(
                  scale.r,
                  stat = "sd", na.rm =
                    T
                ))
            ))
          }
        }
        if (normalize == TRUE) {
          scale.r.norm <-
            (scale.r.norm - as.numeric(terra::global(
              scale.r.norm,
              stat = "min", na.rm =
                T
            ))) / (as.numeric(terra::global(
              scale.r.norm,
              stat = "max", na.rm =
                T
            )) - as.numeric(terra::global(
              scale.r.norm,
              stat = "min", na.rm =
                T
            )))
        }
        return(scale.r.norm)
      }
    

    Let's a benchmark:

    library(terra)
    library(raster)
    library(spatialEco)
    library(microbenchmark)
    
    f <- system.file("ex/elev.tif", package="terra")
    r <- terra::rast(f)
    p <- raster::raster(f)
    microbenchmark(raster=hsp(p),terra=terra_hsp(r),times=10)
    
    Unit: milliseconds
       expr       min       lq      mean    median        uq      max neval cld
     raster 5270.0466 5283.754 5438.2693 5310.7328 5360.2034 6554.091    10   b
      terra  169.9311  171.102  174.4463  174.3601  177.5812  180.184    10  a 
    

    Theterra function is 30 times faster!!! Which is already a good improvement