The default behavior of lidR is to work by chunk or region of interest in such a way that the extent of the collection is covered by the chunks and that the output is a wall-to-wall output. You have perfectly understood the problem. Your files are too close to each other so it loads a portion of the neighbors that overlap the bounding box.
Your idea of using buffer = 0
+ chunk = 0
is correct but does not actually works because you want to process strictly independent files. In short you want to loop through files. The problem is that the package is designed to processed non-independent files and to produce a continuous wall-to-wall output.
You can use
opt_independent_file(ctg) <- TRUE
This will set buffer = 0, chunk = 0 and disable wall-to-wall guarantees. This is equivalent to
opt_chunk_size(ctg) <- 0
opt_chunk_buffer(ctg) <- 0
opt_wall_to_wall(ctg) <- FALSE
But yet it won't work because grid_metrics
does not respects the buffer (this is mentioned in the doc) and always adds a small buffer to guarantee a strict wall-to-wall output. Your case was not actually planned and must be enhancedfixed internally. This will be improved in next release (v3.0.2).
Thus your last option (waiting next release) is to loop manually. No buffer, by file, no wall-to-wall guarantees make the engine being a regular loop actually.
for (file in ctg$filename)
{
las = readLAS(file, filter = "-drop_z_above 1.3 -drop_class 2")
m = grid_metrics(...)
writeRaster(m, ...)
}