rgisrasterterra

Multiplying two rasters having different cell sizes in R


I want to multiply Landsat 30m resolution image with an ERA5 raster of about 25km resolution. I can downscale ERA5 to 30m but it would increase processing. I am just wondering is it possible that whichever 30m cells overlap with 25km cell, these 30m cells get multiplied by single value from 25km cell.

library(terra)
### 1st raster
ETrF <- rast(ncols=4, nrows=4, xmin=73, xmax=75, ymin=31, ymax=33)
### 2nd raster
ET0 <- rast(ncols=2, nrows=2, xmin=73, xmax=75, ymin=31, ymax=33)
### Random values assigned to both rasters
values(ETrF) <- c(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8)
values(ET0) <- c(5,1,2,4)

### Now 1st cell of ET0 (value: 5) will overlap with 1st,2nd,5th and 6th cells (values: 0.1,0.2,0.5,0.6) 
### of ETrF.Is it possible that 5 gets multiplied with 0.1,0.2,0.5 and 0.6 and final output 
### keeps ETrFs resolution.

ETa <- ETrF*ET0.....?

Solution

  • A reason for not implementing that is that you need to chose how to resample the data; x * y cannot capture that.

    In your case, the default bilinear interpolation is probably the most reasonable option when using resample (unless you need a more sophisticated methods that use elevation and other covariables).

    But it does not give the same results as with the extract method. (you need to use resample( , method="near") for that). With the toy data, you can also use disagg.

    If you want to use the extract route, that can be made much more efficient by avoiding the coercion to sf, at least for this toy example:

    fastextr <- function(coarse, fine, method="simple") {
        xy <- crds(fine)
        value <- extract(coarse, xy, method=method) * values(fine)
        rasterize(xy, fine, value)
    }
    
    microbenchmark::microbenchmark(
        "res" = terra::resample(ET0, ETrF, "near", threads = TRUE) * ETrF,
        "mutat" = extract_mutate_rasterize(ET0, ETrF),
        "disagg" = terra::disagg(ET0, 2) * ETrF,
        "fextr" = fastextr(ET0, ETrF), 
        times = 50
    ) 
    
    #Unit: milliseconds
    #   expr     min      lq      mean   median      uq     max neval
    #    res  6.2586  6.4362  6.948614  6.67490  6.8020 21.1767    50
    #  mutat 38.6304 39.4301 40.627638 40.08070 41.1208 58.3876    50
    # disagg  4.5824  4.6490  5.158002  4.77420  4.9126 21.7821    50
    #  fextr  7.9329  8.1154  8.468164  8.44225  8.6150 11.1409    50
    

    So your best option is to use bilinear resampling

    bres <- terra::resample(ET0, ETrF, "bilinear", threads = TRUE) * ETrF
    

    The same result can be obtained with bilinear extract

    bextr <- fastextr(ET0, ETrF, "bilinear")
    

    This extract approach is not much slower than the resample approach for this example. But I would not use the extract method because it may cause problems with memory allocation if you are using large raster data.