My goal is to create a multi-band Sentinel 2 mosaic that includes the most recent cloud/shadow-free observation for each pixel from a date range (e.g. 2021-04-01 thru 2021-06-15). I am going to be running this process for a very large area and for five time windows using the batch processing API so I am looking for any advice on ways to make this query more efficient with respect to processing units.
I have tested it out using the Requests Builder and I believe it is doing what I want based on date-wise viewing in the EO Browser but I am not exactly sure if my valid pixel indexing approach is truly taking the most recent observation so any guidance would be appreciated!
Here is the evalscript that I have so far:
//VERSION=3
function setup() {
return {
input: [{
bands: [
"B04", // red
"B03", // green
"B02", // blue
"B08", // nir
"B11", // swir
"B12",
"SCL", // pixel classification
"CLM" // sen2cloudless mask
],
units: "DN"
}],
output: [
{
id: "default",
bands: 6,
sampleType: SampleType.UINT16
}
],
mosaicking: "ORBIT"
};
}
function filterScenes (scenes, inputMetadata) {
return scenes.filter(function (scene) {
return scene.date.getTime()>=(inputMetadata.to.getTime()-12*31*24*3600*1000);
});
}
// marks pixels marked as clouds/shadows as invalid
function validate(samples) {
var scl = samples.SCL;
var clm = samples.CLM;
if (scl === 3) { // SC_CLOUD_SHADOW
return false;
} else if (clm === 1) { // CLM = cloud
return false;
} else if (scl === 9) { // SC_CLOUD_HIGH_PROBA
return false;
} else if (scl === { // SC_CLOUD_MEDIUM_PROBA
return false;
} else if (scl === 7) { // SC_CLOUD_LOW_PROBA
// return false;
} else if (scl === 10) { // SC_THIN_CIRRUS
return false;
} else if (scl === 11) { // SC_SNOW_ICE
return false;
} else if (scl === 1) { // SC_SATURATED_DEFECTIVE
return false;
} else if (scl === 2) { // SC_DARK_FEATURE_SHADOW
// return false;
}
return true;
}
function evaluatePixel(samples, scenes) {
var clo_b02 = [];
var clo_b03 = [];
var clo_b04 = [];
var clo_b08 = [];
var clo_b11 = [];
var clo_b12 = [];
var a = 0;
for (var i = 0; i < samples.length; i++) {
var sample = samples[i];
if (sample.B02 > 0 && sample.B03 > 0 && sample.B04 > 0 && sample.B08 > 0 && sample.B11 > 0, sample.B12 > 0) {
var isValid = validate(sample);
if (isValid) {
clo_b02[a] = sample.B02;
clo_b03[a] = sample.B03;
clo_b04[a] = sample.B04;
clo_b08[a] = sample.B08;
clo_b11[a] = sample.B11;
clo_b12[a] = sample.B12;
a = a + 1;
}
}
}
rValue = clo_b04[1]; // take first in sequence of valid pixels (most recent?)
gValue = clo_b03[1];
bValue = clo_b02[1];
nValue = clo_b08[1];
sValue = clo_b11[1];
s2Value = clo_b12[1];
return {
default: [rValue, gValue, bValue, nValue, sValue, s2Value]
};
}