Interpreting QC
Opened this issue · 2 comments
I didn't find much useful information for how to interpret the quality control information accessible through MODISTools downloads of respective bands. I wrote the following code (see also here for MOD13Q1 and here for MCD15A3H). I thought I post it here not as an actual "issue", and also not as an definite instruction for others, but rather as a call for others to point out possible errors or misinterpretations here. (I hard-coded a qc-flag-based filtering in the ingestr package, which provides yet another wrapper around MODISTools and more, see here).
For MCD15A3H (band FparLai_QC
) interpreted according to this document:
df <- df %>%
## separate into bits
rowwise() %>%
mutate(qc_bitname = intToBits( qc )[1:8] %>% rev() %>% as.character() %>% paste(collapse = "")) %>%
## MODLAND_QC bits
## 0: Good quality (main algorithm with or without saturation)
## 1: Other quality (backup algorithm or fill values)
mutate(qc_bit0 = substr( qc_bitname, start=8, stop=8 )) %>%
mutate(good_quality = ifelse( qc_bit0=="0", TRUE, FALSE )) %>%
## Sensor
## 0: Terra
## 1: Aqua
mutate(qc_bit1 = substr( qc_bitname, start=7, stop=7 )) %>%
mutate(terra = ifelse( qc_bit1=="0", TRUE, FALSE )) %>%
## Dead detector
## 0: Detectors apparently fine for up to 50% of channels 1, 2
## 1: Dead detectors caused >50% adjacent detector retrieval
mutate(qc_bit2 = substr( qc_bitname, start=6, stop=6 )) %>%
mutate(dead_detector = ifelse( qc_bit2=="1", TRUE, FALSE )) %>%
## CloudState
## 00 0 Significant clouds NOT present (clear)
## 01 1 Significant clouds WERE present
## 10 2 Mixed cloud present in pixel
## 11 3 Cloud state not defined, assumed clear
mutate(qc_bit3 = substr( qc_bitname, start=4, stop=5 )) %>%
mutate(CloudState = ifelse( qc_bit3=="00", 0, ifelse( qc_bit3=="01", 1, ifelse( qc_bit3=="10", 2, 3 ) ) )) %>%
## SCF_QC (five level confidence score)
## 000 0 Main (RT) method used, best result possible (no saturation)
## 001 1 Main (RT) method used with saturation. Good, very usable
## 010 2 Main (RT) method failed due to bad geometry, empirical algorithm used
## 011 3 Main (RT) method failed due to problems other than geometry, empirical algorithm used
## 100 4 Pixel not produced at all, value couldn???t be retrieved (possible reasons: bad L1B data, unusable MOD09GA data)
mutate(qc_bit4 = substr( qc_bitname, start=1, stop=3 )) %>%
mutate(SCF_QC = ifelse( qc_bit4=="000", 0, ifelse( qc_bit4=="001", 1, ifelse( qc_bit4=="010", 2, ifelse( qc_bit4=="011", 3, 4 ) ) ) ))
And for MOD13Q1 (band 250m_16_days_VI_Quality
) based on this document:
df <- df %>%
## separate into bits
rowwise() %>%
mutate(qc_bitname = intToBits( qc ) %>% as.character() %>% paste(collapse = "")) %>%
## Bits 0-1: VI Quality
## 00 VI produced with good quality
## 01 VI produced, but check other QA
mutate(vi_quality = substr( qc_bitname, start=1, stop=2 )) %>%
## Bits 2-5: VI Usefulness
## 0000 Highest quality
## 0001 Lower quality
## 0010 Decreasing quality
## 0100 Decreasing quality
## 1000 Decreasing quality
## 1001 Decreasing quality
## 1010 Decreasing quality
## 1100 Lowest quality
## 1101 Quality so low that it is not useful
## 1110 L1B data faulty
## 1111 Not useful for any other reason/not processed
mutate(vi_useful = substr( qc_bitname, start=3, stop=6 )) %>%
## Bits 6-7: Aerosol Quantity
## 00 Climatology
## 01 Low
## 10 Intermediate
## 11 High
mutate(aerosol = substr( qc_bitname, start=7, stop=8 )) %>%
## Bit 8: Adjacent cloud detected
## 0 No
## 1 Yes
mutate(adjcloud = substr( qc_bitname, start=9, stop=9 )) %>%
## Bits 9: Atmosphere BRDF Correction
## 0 No
## 1 Yes
mutate(brdf_corr = substr( qc_bitname, start=10, stop=10 )) %>%
## Bits 10: Mixed Clouds
## 0 No
## 1 Yes
mutate(mixcloud = substr( qc_bitname, start=11, stop=11 )) %>%
## Bits 11-13: Land/Water Mask
## 000 Shallow ocean
## 001 Land (Nothing else but land)
## 010 Ocean coastlines and lake shorelines
## 011 Shallow inland water
## 100 Ephemeral water
## 101 Deep inland water
## 110 Moderate or continental ocean
## 111 Deep ocean
mutate(mask = substr( qc_bitname, start=12, stop=14 )) %>%
## Bits 14: Possible snow/ice
## 0 No
## 1 Yes
mutate(snowice = substr( qc_bitname, start=15, stop=15 )) %>%
## Bits 15: Possible shadow
## 0 No
## 1 Yes
mutate(shadow = substr( qc_bitname, start=16, stop=16 ))
Here df
is a data frame with column qc
containing integers downloaded as the respective QC band.
Thanks a million, this is great.
I'll add it to the vignette if I find the time!
Pinned it so people find it quickly!