1
|
#!/usr/bin/python
|
2
|
#
|
3
|
# Python test script using GRASS to load 8 daily LST grids and calculate
|
4
|
# pixel-wise averages excluding missing values, for comparison against
|
5
|
# the corresponding 8-day LST product obtained from LP DAAC. Script is
|
6
|
# hard-coded to use the 8-day LST grid for tile h09v04 on 2000.03.05,
|
7
|
# for no particular reason. Also compares the observed count of non-null
|
8
|
# daily LST values (0-8) to the number of clear sky days as indicated in
|
9
|
# the 8-day Clear_sky_days layer.
|
10
|
#
|
11
|
# 8-day target:
|
12
|
# MOD11A2.A2000065.h09v04.005.2007176162644.hdf
|
13
|
#
|
14
|
# Note that it appears Version 5 8-day means were rounded to the nearest
|
15
|
# integer, as implemented below. However, reproducing the Version 4
|
16
|
# product instead appears to require truncating the mean. This
|
17
|
# difference can be expressed as follows in terms of GRASS mapcalc,
|
18
|
# where 'sum' and 'n' are integer rasters:
|
19
|
# * v004: sum/n <-- integer division
|
20
|
# * v005: round(float(sum)/n) <-- floating point division, then round
|
21
|
#
|
22
|
# Script can be run from within an existing GRASS 7 session; all work is
|
23
|
# done within a temporary LOCATION that gets removed at the end.
|
24
|
# Untested in earlier versions of GRASS.
|
25
|
#
|
26
|
# Jim Regetz
|
27
|
# NCEAS
|
28
|
# 16-May-2012
|
29
|
|
30
|
import os, glob, shutil
|
31
|
import numpy as np
|
32
|
import grass.script as gs
|
33
|
import grass.script.array as garray
|
34
|
|
35
|
tmp_location = 'tmp' + str(os.getpid())
|
36
|
orig_location = gs.gisenv()['LOCATION_NAME']
|
37
|
orig_mapset = gs.gisenv()['MAPSET']
|
38
|
|
39
|
gs.os.environ['GRASS_OVERWRITE'] = '1'
|
40
|
|
41
|
# load 11A2 (8-day) tile of interest
|
42
|
name_of_8day_hdf = 'MOD11A2.A2000065.h09v04.005.2007176162644.hdf'
|
43
|
# first load daytime LST
|
44
|
lst8day = 'HDF4_EOS:EOS_GRID:%s/%s:%s' % (
|
45
|
'/home/layers/data/climate/MOD11A2.005-8day-1km-L3-LST',
|
46
|
name_of_8day_hdf,
|
47
|
'MODIS_Grid_8Day_1km_LST:LST_Day_1km')
|
48
|
gs.run_command('r.in.gdal', input=lst8day, output='LST_8day_h09v04',
|
49
|
location=tmp_location)
|
50
|
|
51
|
# switch to new location
|
52
|
gs.run_command('g.gisenv', set='LOCATION_NAME=%s' % tmp_location)
|
53
|
gs.run_command('g.gisenv', set='MAPSET=PERMANENT')
|
54
|
|
55
|
# set GRASS region to match
|
56
|
gs.run_command('g.proj', flags='c',
|
57
|
proj4='+proj=sinu +a=6371007.181 +b=6371007.181 +ellps=sphere')
|
58
|
gs.run_command('g.region', rast='LST_8day_h09v04')
|
59
|
|
60
|
# now load clear sky days and generate count raster
|
61
|
csd8day = 'HDF4_EOS:EOS_GRID:%s/%s:%s' % (
|
62
|
'/home/layers/data/climate/MOD11A2.005-8day-1km-L3-LST',
|
63
|
name_of_8day_hdf,
|
64
|
'MODIS_Grid_8Day_1km_LST:Clear_sky_days')
|
65
|
gs.run_command('r.in.gdal', input=csd8day, output='CSD_8day_h09v04')
|
66
|
gs.mapcalc('nCSD_8day_h09v04 = %s' %
|
67
|
'+'.join(['((CSD_8day_h09v04 >> %d) & 1)' % pos for pos in range(8)]))
|
68
|
|
69
|
# load the corresponding dailies
|
70
|
ordir = '/home/layers/data/climate/MOD11A1.004-OR-orig-2000'
|
71
|
LST = list()
|
72
|
CDC = list()
|
73
|
for doy in range(65, 72+1):
|
74
|
pathglob = os.path.join(ordir, 'MOD11A1.A2000%03d.h09v04*hdf' % doy)
|
75
|
try:
|
76
|
hdfpath = glob.glob(pathglob)[0]
|
77
|
except:
|
78
|
print '*** problem finding', pathglob, '***'
|
79
|
continue
|
80
|
hdfname = os.path.basename(hdfpath)
|
81
|
LST.append('LST_' + '_'.join(hdfname.split('.')[1:3]))
|
82
|
gs.run_command('r.in.gdal',
|
83
|
input='HDF4_EOS:EOS_GRID:%s:MODIS_Grid_Daily_1km_LST:LST_Day_1km' % hdfpath,
|
84
|
output=LST[-1])
|
85
|
CDC.append('CDC_' + '_'.join(hdfname.split('.')[1:3]))
|
86
|
gs.run_command('r.in.gdal',
|
87
|
input='HDF4_EOS:EOS_GRID:%s:MODIS_Grid_Daily_1km_LST:Clear_day_cov' % hdfpath,
|
88
|
output=CDC[-1])
|
89
|
|
90
|
# generate the 8-day mean and number of observations
|
91
|
numerator = '(%s)' % '+'.join(['if(isnull(%s), 0, %s)' % (m, m)
|
92
|
for m in LST])
|
93
|
denominator = '(%s)' % '+'.join(['if(!isnull(%s))' % m
|
94
|
for m in LST])
|
95
|
gs.mapcalc('nobs_LST_h09v04 = %s' % denominator)
|
96
|
gs.mapcalc('mean_LST_h09v04 = round(float(%s)/nobs_LST_h09v04)' % numerator)
|
97
|
|
98
|
# generate the 8-day sum of Clear_day_cov
|
99
|
gs.mapcalc('sum_CDC_h09v04 = %s' % '+'.join(['if(isnull(%s), 0, %s)' % (m, m)
|
100
|
for m in CDC]))
|
101
|
|
102
|
gs.os.environ['GRASS_OVERWRITE'] = '0'
|
103
|
|
104
|
# compare LST grid values and report out...
|
105
|
mean_theirs = garray.array()
|
106
|
mean_theirs.read('LST_8day_h09v04')
|
107
|
print 'Average of their 8-day product:', mean_theirs.mean()
|
108
|
mean_ours = garray.array()
|
109
|
mean_ours.read('mean_LST_h09v04')
|
110
|
print 'Average of our 8-day product:', mean_ours.mean()
|
111
|
if (mean_ours==mean_theirs).all():
|
112
|
print 'Successfully reproduced LST_Day_1km from', name_of_8day_hdf
|
113
|
else:
|
114
|
print 'Failed to reproduce LST_Day_1km from', name_of_8day_hdf
|
115
|
|
116
|
# compare nObs grid values and report out...
|
117
|
nobs_theirs = garray.array()
|
118
|
nobs_theirs.read('nCSD_8day_h09v04')
|
119
|
print 'Average of counts based on Clear_sky_days:', nobs_theirs.mean()
|
120
|
nobs_ours = garray.array()
|
121
|
nobs_ours.read('nobs_LST_h09v04')
|
122
|
print 'Average of our N_obs:', nobs_ours.mean()
|
123
|
if (nobs_ours==nobs_theirs).all():
|
124
|
print 'Successfully reproduced Clear_sky_days counts from', name_of_8day_hdf
|
125
|
else:
|
126
|
print 'Failed to reproduce Clear_sky_days counts from', name_of_8day_hdf
|
127
|
|
128
|
# clean up
|
129
|
gs.run_command('g.gisenv', set='LOCATION_NAME=%s' % orig_location)
|
130
|
gs.run_command('g.gisenv', set='MAPSET=%s' % orig_mapset)
|
131
|
shutil.rmtree(os.path.join(gs.gisenv()['GISDBASE'], tmp_location))
|