0

I am working with MODIS snow cover products (MOD10A1) and am unable to understand some of the values that are returned. I am trying to get % snow cover from the NDSI (normalised difference snow index) snow cover layer. The MODIS user manual states that the NDSI snow cover layer has values from 0 - 100, representing % snow cover in each pixel, and eight values between 200 and 255 that represent all other possible features/masks (cloud, missing data etc). In processing the images I am finding values between 100 and 200 and cannot find any reference to such values in the MODIS documentation.

I downloaded the MOD10A1 product as .hd files from the NSIDC.org site. I work in R, but have not been able to work with the .hd files in R, so I converted the NDSI snow cover layer to .tif files using the HEG converter program that is recommended on the MODIS NASA website. I imported the .tif files into RStudio using the raster package and used the getValues and unique functions to find the value in each pixel. The returned values are anything from 0 to 255, including values in the range 100-200.

Does anyone know what these values mean? Have they come with the product or is there an error in the file conversion? Thank you for your help.

EDIT: thanks for the suggestion. One of the exact file names is 'MOD10A1.A2015364.h25v06.006.2016182181418.hdf' and a link to the file https://drive.google.com/file/d/1HeEpIL15EC_PSBWsuGT4FJMZOPr4_oND/view?usp=sharing

I have tried using the rast function in the terra package and get the same result.

AWB
  • 13
  • 3
  • Can you point to the exact file (or at least the exact filename) and ideally, share the file. You can read these files directly with the "terra" package, and that may save you a lot of trouble. – Robert Hijmans Dec 07 '20 at 00:48

1 Answers1

0

You can look at this with terra.

library(terra)
f <- "MOD10A1.A2015364.h25v06.006.2016182181418.hdf"

You can do

x <- rast(f)
names(x)
#[1] "MOD_Grid_Snow_500m:NDSI_Snow_Cover"                    "MOD_Grid_Snow_500m:NDSI_Snow_Cover_Basic_QA"          
#[3] "MOD_Grid_Snow_500m:NDSI_Snow_Cover_Algorithm_Flags_QA" "MOD_Grid_Snow_500m:NDSI"                              
#[5] "MOD_Grid_Snow_500m:Snow_Albedo_Daily_Tile"             "MOD_Grid_Snow_500m:orbit_pnt"                         
#[7] "MOD_Grid_Snow_500m:granule_pnt"                       
 

And use the first layer

ndsisc <- x[[1]]
ndsisc
#class       : SpatRaster 
#dimensions  : 2400, 2400, 1  (nrow, ncol, nlyr)
#resolution  : 463.3127, 463.3127  (x, y)
#extent      : 7783654, 8895604, 2223901, 3335852  (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs 
#source      : MOD10A1.A2015364.h25v06.006.2016182181418.hdf:MOD_Grid_Snow_500m:NDSI_Snow_Cover 
#names       : MOD_Grid_Snow_500m:NDSI_Snow_Cover 

Or acknowledge the sub-dataset structure of the file

s <- sds(f)
s
#class       : SpatDataSet 
#subdatasets : 7 
#dimensions  : 2400, 2400 (nrow, ncol)
#nlyr        : 1, 1, 1, 1, 1, 1, 1 
#resolution  : 463.3127, 463.3127  (x, y)
#extent      : 7783654, 8895604, 2223901, 3335852  (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs 
#source(s)   : MOD10A1.A2015364.h25v06.006.2016182181418.hdf 
#names       : NDSI_Snow_Cover, NDSI_Snow_Cover_Basic_QA, NDSI_Snow_Cover_Algorithm_Flags_QA, NDSI, Snow_Albedo_Daily_Tile, orbit_pnt, granule_pnt 

names(s)
#[1] "NDSI_Snow_Cover"                    "NDSI_Snow_Cover_Basic_QA"           "NDSI_Snow_Cover_Algorithm_Flags_QA"
#[4] "NDSI"                               "Snow_Albedo_Daily_Tile"             "orbit_pnt"                         
[7] "granule_pnt"  

And use the first sub-dataset

ndsisc <- s[1]
ndsisc
#class       : SpatRaster 
#dimensions  : 2400, 2400, 1  (nrow, ncol, nlyr)
#resolution  : 463.3127, 463.3127  (x, y)
#extent      : 7783654, 8895604, 2223901, 3335852  (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs 
#source      : MOD10A1.A2015364.h25v06.006.2016182181418.hdf:MOD_Grid_Snow_500m:NDSI_Snow_Cover 
#names       : NDSI snow cover from best observation of the day 
 

Now check the values with freq (or unique)

fq <- freq(ndsisc)
tail(fq)
#      layer value  count
#[84,]     1    92     28
#[85,]     1    93     15
#[86,]     1    94      3
#[87,]     1   201  33636
#[88,]     1   237  37178
#[89,]     1   250 807785

There are values below 100 and above 200, but not in between, as you assert.

A next step could be

nd <- clamp(ndsisc, 0, 100, values=FALSE)
nd
#class       : SpatRaster 
#dimensions  : 2400, 2400, 1  (nrow, ncol, nlyr)
#resolution  : 463.3127, 463.3127  (x, y)
#extent      : 7783654, 8895604, 2223901, 3335852  (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs 
#source      : memory 
#names       : NDSI snow cover from best observation of the day 
#min values  :                                                0 
#max values  :                                               94  

Perhaps you where accidentally using the "Snow_Albedo_Daily_Tile" subdataset?

albedo <- s[5]
albedo
#class       : SpatRaster 
#dimensions  : 2400, 2400, 1  (nrow, ncol, nlyr)
#resolution  : 463.3127, 463.3127  (x, y)
#extent      : 7783654, 8895604, 2223901, 3335852  (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs 
#source      : MOD10A1.A2015364.h25v06.006.2016182181418.hdf:MOD_Grid_Snow_500m:Snow_Albedo_Daily_Tile 
#names       : Snow albedo of the corresponding snow cover observation 

That one has values between 100 and 200. But is that unexpected?

as.vector(unique(albedo))
#[1]   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30
#[32]  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61
#[63]  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  88  91  92  93  94  95
#[94] 100 101 125 137 150 251 253
Robert Hijmans
  • 40,301
  • 4
  • 55
  • 63
  • Thank you Robert. I was quite sure I was using the snow cover layer, but your answer makes sense. The albedo layer does have values in the range 100-200 that represent additional categories. Now to get R to recognise gdal install so I can use terra... – AWB Dec 08 '20 at 03:06
  • What OS are you on? Installing terra is a no-brainer on windows, simple on linux, and not too bad on mac with homebrew. Some instructions here: https://github.com/rspatial/terra – Robert Hijmans Dec 08 '20 at 03:42
  • Mojave 10.14.6. I have tried installing both MODIS and terra packages a number of times, installing, uninstalling, linking packages and setting paths and so on. When I followed the instructions on you git_hub just now, the install failed when libproj.19.dylib could not be located. – AWB Dec 08 '20 at 20:41
  • perhaps you need *"--with-proj-lib=/usr/local/lib/")* see https://github.com/r-spatial/sf I do not need it on Catalina – Robert Hijmans Dec 08 '20 at 22:37
  • FYI, Robert, I gave up trying to get terra working on my laptop. The IT guy at uni reckons there are a ton of incompatibilities between the programs and packages and so on with my OS. Instead I am using terra on the university's remote server and it is working well. Thanks. – AWB Dec 18 '20 at 01:56