r-lidar / lidR

Airborne LiDAR data manipulation and visualisation for forestry application
https://CRAN.R-project.org/package=lidR
GNU General Public License v3.0
606 stars 132 forks source link

Windows-specific "could not find function" Error #165

Closed bi0m3trics closed 6 years ago

bi0m3trics commented 6 years ago

Hey JR. In 1.6.0 I've encountered what I think is a Windows-specific error (i.e., this does not occur on either of my linux machines) when using catalog_apply. In short, when I run the help documentation example code for catalog_apply, I receive the following error message: Error in myMetrics(X, Y, Z, buffer) : could not find function "myMetrics" with the following information being supplied from Traceback:

8. stop(e) at clusters_apply.r#99
7. value[[3L]](cond) 
6. tryCatchOne(expr, names, parentenv, handlers[[1L]]) 
5. tryCatchList(expr, classes, parentenv, handlers) 
4. tryCatch({
    x = future::value(future)
    if (!is.null(x)) 
        return(ASYNC_OK) ... at clusters_apply.r#90
3. early_eval(output[[j]], stop_early) at clusters_apply.r#54
2. cluster_apply(clusters, cluster_apply_func, ncores, progress, 
    stopearly, func = func, ctg = ctg, func_args = func_args, 
    ...) at catalog_apply.r#179
1. catalog_apply(project, tree_area, fargs, select = "xyz")

For completeness, this error does not occur with 1.6.0 in Linux Mint 18.3 or Ubuntu 18.04, so I could not supply a reproducible error in both Linux & Windows...

After some reading here, I believe the issue is with the new code within the cluster_apply (line 45, the asynchronous computation call) and is due to myMetrics (or any other user-defined function) not being global and thus not being available to the clusters.

For what it's worth (the following isn't a solution, but rather a check to see if the call to future::future is indeed the culprit), replacing line 45 with the following call completely eliminated the error and the code executed fine on the two Windows 10 machines I tested it on... Existing code that triggers an error:

output[[i]] <- future::future({ 
  f(clusters[[i]], ...)
  }, substitute = TRUE, packages = required.pkgs)

Code with myMetricssupplied as a missing global in call to future::futureresulting in proper execution:

output[[i]] <- future::future({
  myMetrics
  f(clusters[[i]], ...)
  }, substitute = TRUE, packages = required.pkgs)

I don't offer a workaround or a solution as I'm sure passing additional arguements (list of user-defined uncitons) to cluster_applywill likely result in a non-trivial fix.

Cheers, Bi0m3trics

Jean-Romain commented 6 years ago

I guess this happens if you set a number of cores > 1 right?

Object exportation in clusters is terribly boring but the origin of the problem is known and reproducible on linux.

Thanks

bi0m3trics commented 6 years ago

Yeah, it works fine with cores = 1. Here's the code, which is a minimally altered version of the catalog_applyexample code:

library(lidR) # 1.6.0

LASfile <- system.file("extdata", "Megaplot.laz", package="lidR")
project = catalog(LASfile)
buffer(project) = 15
cores(project) = 8
tiling_size(project) = 120
progress(project) = TRUE

folder <- system.file("extdata", "", package="lidR")
lake_shp = rgdal::readOGR(folder, "lake_polygons_UTM17")

myMetrics <- function(x, y, z, buff)
{
  i = which.max(z)
  xcenter = x[i]
  ycenter = y[i]
  A = area(x,y)
  minbuff = min(buff)
  maxbuff = max(buff)

  return(
    list(
      x = xcenter,
      y = ycenter,
      area = A,
      minbuff = minbuff,
      maxbuff = maxbuff
    ))
}

tree_area = function(las, lake)
{
  lasclassify(las, lake, field = "lake")
  las = lasfilter(las, lake == FALSE, Z > 4)
  if (is.null(las))
    return(NULL)
  lastrees(las, algorithm = "li2012-2")

  m = tree_metrics(las, myMetrics(X, Y, Z, buffer))
  m = m[minbuff == 0 & maxbuff <= 2]
  m[, c("minbuff","maxbuff") := NULL]

  return(m)
}

fargs = list(lake = lake_shp)
output = catalog_apply(project, tree_area, fargs, select = "xyz")

which produces Error in myMetrics(X, Y, Z, buffer) : could not find function "myMetrics"

Jean-Romain commented 6 years ago

That's ok I reproduced the bug. I read your issue too fast and I missed that it was with the example of the doc...

What I don't understand is that this code used to work... :disappointed:

Jean-Romain commented 6 years ago

Fixed with a dirty patch. It does not matter. v2.0 is coming. That will not be relevant anymore.

bi0m3trics commented 6 years ago

Thanks! I'll give it a go here in a bit when I'm back at the computer. I debated on even reporting the bug, but ultimately figured some are still working off a devtools::install_github version or something similar and in the interim they might want it fixed...

Jean-Romain commented 6 years ago

Rule of thumb: if an example of the docs does not work, report it, this is not an expected behavior! :wink: