Revision 9b802e31
Added by Alberto Guzman about 11 years ago
climate/research/oregon/modis-lst/modis_LST_mean.py | ||
---|---|---|
1 |
#Calculates monthly mean for date range. Uses MOD11A1 tiles in specified directory |
|
2 |
#Assumes MOD11A1.005/2000.03.05/MOD11A1.A2000065.h08v04.005.2007176143143.hdf directory structure |
|
3 |
#Non optimized version. Could use Cython to compile C++ fuctions to make it faster. |
|
4 |
#Can do single tile or read list from file. |
|
5 |
#--------------------------------------------------------------------------- |
|
6 |
# Developed by Alberto Guzman |
|
7 |
# 09/15/2013 |
|
8 |
|
|
9 |
import sys, numpy |
|
10 |
import netCDF4, datetime,os |
|
11 |
import glob |
|
12 |
from optparse import OptionParser |
|
13 |
from pyhdf.SD import SD |
|
14 |
import gdal |
|
15 |
|
|
16 |
def main(): |
|
17 |
usage = "usage: %prog [options] <indDir> <outDir> \n"+\ |
|
18 |
"Calculates monthly mean for MOD11A1 tiles in specified directory" |
|
19 |
parser = OptionParser(usage=usage) |
|
20 |
parser.add_option("-s","--yStart",dest="yStart",default=2000, |
|
21 |
help="Start year to process") |
|
22 |
parser.add_option("-e","--yEnd",dest="yEnd",default=2010, |
|
23 |
help="End year to process") |
|
24 |
parser.add_option("-m","--months",dest="months",default='1,2,3,4,5,6,7,8,9,10,11,12', |
|
25 |
help="Comma separated list of months to process (1,2,3...12),default all") |
|
26 |
parser.add_option("-f","--outputFormat",dest="outF",default="flt", |
|
27 |
help="Format of output, currently flt(no projection info) and geotif supported") |
|
28 |
parser.add_option("-d","--daynight",dest="dn",default="0", |
|
29 |
help="Use 0 for both(default),1 for day only,2 for night only") |
|
30 |
parser.add_option("-t","--tile",dest="tile",default="h08v04", |
|
31 |
help="Which modis tile to process by default uses h08v04") |
|
32 |
parser.add_option("-l","--tileList",dest="tiles",default=None, |
|
33 |
help="Get tiles list from file(one per line), overwrites option 't'") |
|
34 |
opts,args=parser.parse_args() |
|
35 |
if len(args)<2: |
|
36 |
sys.exit(parser.print_help()) |
|
37 |
|
|
38 |
inDir = args[0] |
|
39 |
outDir = args[1] |
|
40 |
|
|
41 |
yStart = int(opts.yStart) |
|
42 |
yEnd = int(opts.yEnd) |
|
43 |
months = opts.months.split(',') |
|
44 |
outFormat = opts.outF |
|
45 |
if (outFormat != "flt") & (outFormat != "tif"): |
|
46 |
print "Error: Only flt or tif output formats supported" |
|
47 |
sys.exit(1) |
|
48 |
|
|
49 |
if int(opts.dn) == 0: |
|
50 |
dayNight = ["Day","Night"] |
|
51 |
elif int(opts.dn) == 1: |
|
52 |
dayNight = ["Day"] |
|
53 |
elif int(opts.dn) == 2: |
|
54 |
dayNight = ["Night"] |
|
55 |
else: |
|
56 |
print "Error: Only 0(both),1(day),2(night) options supported" |
|
57 |
sys.exit(1) |
|
58 |
|
|
59 |
#Check if in and out directory exist, create out if it doesn't |
|
60 |
if os.path.exists(inDir) is False: |
|
61 |
print "Error: %s directory doesn't exists" % inDir |
|
62 |
sys.exit(1) |
|
63 |
if os.path.exists(outDir) is False: |
|
64 |
print "Warning: %s directory doesn't exists, creating directory" % outDir |
|
65 |
|
|
66 |
if opts.tiles is not None: |
|
67 |
if os.path.exists(opts.tiles) is False: |
|
68 |
print "Error: file %s doesn't exists" % opts.tiles |
|
69 |
sys.exit(1) |
|
70 |
else: |
|
71 |
fPtr = open(opts.tiles) |
|
72 |
if fPtr is None: |
|
73 |
print "Error: Opening file %s" % opts.tiles |
|
74 |
sys.exit(1) |
|
75 |
else: |
|
76 |
tiles = [] |
|
77 |
for t in fPtr.readlines(): |
|
78 |
tiles.append(t.rstrip()) |
|
79 |
fPtr.close() |
|
80 |
else: |
|
81 |
tiles = [opts.tile] |
|
82 |
|
|
83 |
#TEST |
|
84 |
#tile = 'h08v04' |
|
85 |
#dayNight = 'day' |
|
86 |
|
|
87 |
print tiles |
|
88 |
for tile in tiles: |
|
89 |
#One log file per tile, it only logs errors messages |
|
90 |
logFn = outDir+'/outlog_'+tile+'.log' |
|
91 |
logPtr = open(logFn,"w+") |
|
92 |
if logPtr is None: |
|
93 |
print "Error: couldn't create log file %s" % logFn |
|
94 |
print "Continuing without log" #should we just exit? |
|
95 |
|
|
96 |
#Use a tile to create out tif if option selected |
|
97 |
tmpFn = '' |
|
98 |
|
|
99 |
print "Processing months %s and years %d-%d for tile %s" % (opts.months,yStart,yEnd,tile) |
|
100 |
for dN in dayNight: |
|
101 |
for m in months: |
|
102 |
#Temp monthly arrays |
|
103 |
meanTotal = numpy.zeros((1200,1200),dtype=numpy.float32) |
|
104 |
nobsTotal = numpy.zeros((1200,1200),dtype=numpy.int32) |
|
105 |
|
|
106 |
mSrc = '%0*d' % (2,int(m)) #setting to two digit format for months < 10 |
|
107 |
for y in range(yStart,yEnd+1): |
|
108 |
#Get list of files assumes MOD11A1.005/2000.03.05/MOD11A1.A2000065.h08v04.005.2007176143143.hdf format |
|
109 |
inFilesSrch = "%s/%d.%s.*/MOD11A1.*.%s.*.hdf" % (inDir,y,mSrc,tile) |
|
110 |
inFiles = glob.glob(inFilesSrch) |
|
111 |
|
|
112 |
if len(inFiles) < 1: |
|
113 |
print "No files found" |
|
114 |
else: |
|
115 |
print "Found %d files" % len(inFiles) |
|
116 |
for f in inFiles: |
|
117 |
print "Processing %s %s" % (f,dN) |
|
118 |
try: |
|
119 |
ds = SD(f) |
|
120 |
dayTemp = ds.select('LST_'+dN+'_1km').get() |
|
121 |
dayTemp = numpy.where(dayTemp > 0,(dayTemp * 0.02) - 273.15,0) # K to C degrees |
|
122 |
|
|
123 |
#We want highest quality so check last two bits for [00] |
|
124 |
qa = ds.select('QC_'+dN).get() & 0b00000011 |
|
125 |
meanTotal = numpy.where((qa == 0) & (dayTemp > 0),meanTotal+dayTemp,meanTotal) |
|
126 |
nobsTotal = numpy.where((qa == 0) & (dayTemp > 0),nobsTotal+1,nobsTotal) |
|
127 |
ds.end() |
|
128 |
|
|
129 |
meanTotal = numpy.where((nobsTotal != 0) & (meanTotal != 0),meanTotal/nobsTotal,0) |
|
130 |
meanTotal = numpy.nan_to_num(meanTotal) |
|
131 |
tmpFn = f |
|
132 |
if logPtr is not None: |
|
133 |
logPtr.write("Processed: "+f+"\n") |
|
134 |
except Exception: |
|
135 |
print "Error reading or accessing file, adding to log" |
|
136 |
if logPtr is not None: |
|
137 |
logPtr.write("Error: "+f+"\n") |
|
138 |
pass |
|
139 |
|
|
140 |
if outFormat == "flt": |
|
141 |
#Save to file, outputs to same grid as original tile |
|
142 |
outFn = "%s/mean_LST_%s_1km_%s_%s.flt32" % (outDir,tile,m,dN) |
|
143 |
meanTotal.tofile(outFn) |
|
144 |
outFn = "%s/nobs_LST_%s_1km_%s_%s.int32" % (outDir,tile,m,dN) |
|
145 |
nobsTotal.tofile(outFn) |
|
146 |
elif outFormat == "tif": |
|
147 |
outFn = "%s/mean_LST_%s_1km_%s_%s.tif" % (outDir,tile,m,dN) |
|
148 |
print "Outputing to", outFn |
|
149 |
out2Tif(meanTotal,outFn,tmpFn) |
|
150 |
outFn = "%s/nobs_LST_%s_1km_%s_%s.tif" % (outDir,tile,m,dN) |
|
151 |
out2Tif(nobsTotal,outFn,tmpFn,1,gdal.GDT_UInt32) |
|
152 |
logPtr.close() |
|
153 |
sys.exit(0) |
|
154 |
|
|
155 |
def out2Tif(outData,outFn,inFn,bands=1,format=gdal.GDT_Float32): |
|
156 |
dims = 1200 |
|
157 |
inDsFn = "HDF4_EOS:EOS_GRID:%s:MODIS_Grid_Daily_1km_LST:LST_Day_1km" % inFn |
|
158 |
inDs = gdal.Open(inDsFn,gdal.GA_ReadOnly) |
|
159 |
if inDs is None: |
|
160 |
print "Error opening %s " % inDsFn |
|
161 |
return None |
|
162 |
|
|
163 |
driver = gdal.GetDriverByName("GTiff") |
|
164 |
metadata = driver.GetMetadata() |
|
165 |
if metadata.has_key(gdal.DCAP_CREATE) and metadata[gdal.DCAP_CREATE] == 'YES': |
|
166 |
d = 1 |
|
167 |
#print 'Driver GTiff supports Create() method.' |
|
168 |
else: |
|
169 |
print 'Driver GTIFF does not support Create()' |
|
170 |
return None |
|
171 |
|
|
172 |
geoTrans = inDs.GetGeoTransform() |
|
173 |
geoProj = inDs.GetProjection() |
|
174 |
|
|
175 |
outDs = driver.Create(outFn,dims,dims,bands,format) |
|
176 |
|
|
177 |
if outDs is None: |
|
178 |
print "Error creating output file %s" % outFn |
|
179 |
sys.exit(1) |
|
180 |
outDs.SetGeoTransform(geoTrans) |
|
181 |
outDs.SetProjection(geoProj) |
|
182 |
|
|
183 |
b1 = outDs.GetRasterBand(1) |
|
184 |
b1.WriteArray(outData) |
|
185 |
|
|
186 |
inDs = None |
|
187 |
outDs = None |
|
188 |
|
|
189 |
return None |
|
190 |
|
|
191 |
if __name__ == '__main__': |
|
192 |
main() |
Also available in: Unified diff
Adding modis_LST_mean.py. Python alternative to grass version. Outputs geotif or flt.