I am trying to compare January's mean composite of MODIS Terra LST 8-Day Global 1km (MOD11A2.061) of the year 2021 processed using two different platforms. The first one is done using python scripts and ArcMap modelbuilder, where data used were retrieved from AppEEARS and decoded with ArcGIS MODIS-VIIRS Python Toolbox. On the other hand, the second composite is made in Google Earth Engine (GEE).

I was surprised to find GEE LST scene was masking larger pixels in compare to ArcMap processed LST. To understand more on it, I started checking each scene - there are 3 scenes in the month of January. After few testing, I found that the "QC_Day" and "Clear_sky_days" bands are already masked (pre-masked) out for some regions/pixels (see QC_Day band image below) and as a result, when I was using qualitybitmask, the pre-masked area of QC_Day band was being added to the qualitybitmask - hence larger pixels were getting masked out.

QC_Day band Inspector panel reveals QC_Day being masked

Now, why is that? I did a moderate googling on this; found nothing on this.

Does the code for qualitybitmask need correction/improvement?

If QC_Day band comes masked, which can be seen in the GEE Map where I mapped it, what does the masked out areas mean, good/bad LST pixel? Data processed in ArcMap seems fine (LST image below).

Link to GEE: It contains only first image of January to keep the code simple.


LST processed in ArcMap

// Data import
var bound = ee.Geometry.Rectangle([[89.31413136361041,7.0070912317613665],[118.6696001136104,29.529464226220604]]);
Map.centerObject(bound, 4.5);

var terra = ee.ImageCollection('MODIS/061/MOD11A2').filter(ee.Filter.date('2022-01-09', '2022-01-10'));
var terra_qc = terra.first().select('QC_Day').clip(bound);
var terra_cs = terra.first().select('Clear_sky_days').clip(bound);

// Quality mask; code adopted from https://spatialthoughts.com/2021/08/19/qa-bands-bitmasks-gee/
var bitwiseExtract = function(input, fromBit, toBit) {
  var maskSize = ee.Number(1).add(toBit).subtract(fromBit);
  var mask = ee.Number(1).leftShift(maskSize).subtract(1);
  return input.rightShift(fromBit).bitwiseAnd(mask);

// Quality filter 
var quality_day = function(img) {
  var lstDay = img.select('LST_Day_1km');
  var qcDay = img.select('QC_Day');
  var emissivityMask = bitwiseExtract(qcDay, 4, 5).lte(1);    // No more than 0.02 emissivity error
  var lstErrorMask = bitwiseExtract(qcDay, 6, 7).lte(1);    // No more than 2K LST error
  var mask = emissivityMask.and(lstErrorMask);
  return lstDay.updateMask(mask);

// Function to clip each image; adding pixel counts to a property, 'pixel_count'
var clipped = function (img) {
   img = img.clip(bound);
   return img

// Function to convert kelvin to degree celcius
var kelvin_celcius = function(img){
  return img

// Quality filter application: imageCollection
var terra_day = terra.map(quality_day)

// Adding layers to map
Map.addLayer(terra_cs, {min:0, max: 255, palette:['black', 'white']}, 'Clear-sky days' );
Map.addLayer(terra_qc, {min:0, max: 255, palette:['black', 'white']}, 'QC_Day' );
Map.addLayer(terra_day.first(), {min: -20, max: 40, palette:['blue','yellow','red']}, 'LST filtered');


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy