The iDivR package accommodates functions to derive global, day/night, monthly LST based on 8-day TERRA (MOD11A2) and AQUA (MYD11A2) data. The functions are supported by embarrassingly parallel processing and the data processing is tile oriented (Fig. 1). For each tile, the algorithm performs the following, general steps:
Figure 1 - Algorithm work flow
While the algorithm uses R, this language serves mainly as a wrapper. When performing RAM demanding tasks such as e.g. mosaicking, the algorithm calls GDAL. The algorithm is provided in the form of an R package and can be installed with devtools as shown below.
devtools::install_github("RRemelgado/iDivR")
Figure 2 - Example output of the gap-filled algorithm
Looking at the LAADS DAAC server, we can see that tiles with no overlapping land masses were already excluded. However, there are still tiles that overlap with very small land masses (i.e. area smaller than the product's pixel resolution). To avoid the time-consuming download of these tiles, I downloaded a shapefile with the world's administrative boundaries (acquired here) and, for each polygon, estimated the percent pixel coverage for a 1200 x 1200m grid (i.e. product grid resolution) using the poly2sample() function of the fieldRS package. This function identifies all the pixels covered by a polygon and, for each pixel, quantifies the percent overlap.
require(fieldRS)
# read auxiliary data
cadm <- shapefile("country administrative boundaries")
tile <- shapefile("MODIS tile shapefile")
# filter polygons where no pixel is completely comtained
cadm.points <- poly2sample(s.tmp, 1200)
cadm <- intersect(cadm, cadm.points[cadm.points$cover == 100,])
# target tiles
tiles <- unique(cadm$tile)
Using this data, I filtered out all polygons where the minimum percent overlap was smaller than 100% (Fig. 3). Then, I downloaded a shapefile with the MODIS tiles (acquired here) and selected the relevant tiles. Considering the build-up of a LST global, monthly composites for 1 year, this step avoided the download of 1.4 Tb of redundant data. These tiles (Fig. 4) overlap with small islands, mostly within the Pacific and Indian Oceans, where the use of satellite data with a higher resolution (e.g. Landsat) would be more appropriate.
Figure 3 - Red circles highlight land masses that were excluded from further processing
Figure 4 - Comparison of MODIS tiles for which LST is avaible tiles (in yellow) and the ones excluded when considering the percent pixel overlap (in red)
To demonstrate the applicability of the code, I derived the following data for the year of 2017 covering all continental Europe:
Figure 6 - Global mosaic with data available for Continental Europe.
I estimated that the processing time for each tile (per year) is as following:
I would improve my codes by generalizing the use of c++ for data processing. This would particularly useful when a High Performance Computer (HPC) is available allowing the data processing to be R independent (Fig. 5). Tasks such as gap filling (see c++ code here) can be done in such a way by first stacking the time-series of LST (as already done), exporting the values as a csv and transferring them to the HPC (Fig.7). When dealing with high resolution data (e.g. Landsat, Sentinel) this process can be preceded by the splitting of the data into small, equal sized parts that can be processed in parallel in the HPC and them recombined into a single Raster object once the processing is completed.
Figure 7 - HPC compatible image processing
Below, I started developing a c++ code to fill data gaps which can be used with e.g. apply() to speed up this process. To my knowledge, c++ tasks are on average 4x faster than their R equivalent.
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp ;
using namespace arma;
// [[Rcpp::export]]
NumericVector intime(NumericVector x, NumericVector y, int z) {
double N = x.size()-1;
NumericVector v = y;
for (int i=1; i< N; i++) {
bool cond = y[i] != y[i];
if (cond) {
int x1 = x[i]-z;
int x2 = x[i]+z;
int i1 = -1;
while (i1 < 0) for (int j=i-1; j > 0; i--) if (is_finite(y[j])) if (x[i] > x1) i1 = j;
int i2 = -1;
while (i1 < 0) for (int j=i+1; j > 0; i++) if (is_finite(y[j])) if (x[i] < x2) i1 = j;
if (i1 > -1) {
if (i2 > -1) {
double a = 0;
double b = 0;
double xsum = x[i1] + x[i2];
double x2sum = pow(x[i1],2) + pow(x[i2],2);
double xsum2 = pow(xsum,2);
double ysum = y[i1] + y[i2];
double xysum = xsum * ysum;
a = (ysum*x2sum - xsum*ysum) / (N*x2sum-xsum2);
b = (N*xysum-(xsum*ysum)) / (N*x2sum-xsum2);
v(i) = b + a * x[i];
}
}
}
}
return v;
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.