OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
dtdb_viirs_l1a.py
Go to the documentation of this file.
1 '''
2 * NAME: dtdb_viirs_l1a.py
3 *
4 * DESCRIPTION: Executable program to automate download of L1A files in specified date-time range.
5 
6 * USAGE: dtdb_viirs_l1a.py -b [start date-time] -e [end date-time] -o [output directory]
7 
8 * Created on February 27, 2021
9 
10 * Author: Samuel Anderson
11 '''
12 
13 import os
14 import sys
15 from datetime import datetime
16 import viirs_files as vf
17 import optparse as optparse
18 import logging
19 LOG = logging.getLogger('dtdb_viirs_l1a')
20 
21 #str_url ="http://oceandata.sci.gsfc.nasa.gov/cgi/getfile/"
22 str_url ="https://oceandata.sci.gsfc.nasa.gov/ob/getfile/"
23 str_wget ="wget --load-cookies ~/.urs_cookies --save-cookies ~/.urs_cookies --auth-no-challenge=on --content-disposition "
24 str_wdir ="-P "
25 
26 def init_dir(inpath):
27  files = []
28  dircontents = os.listdir(inpath)
29  dircontents.sort()
30  for x in dircontents:
31  if x[0] == ".":
32  continue
33  infilepath = inpath + x
34  if not os.path.isfile(infilepath):
35  continue
36  files.append(infilepath)
37  return files
38 
39 def hour2min(hour, min):
40  tot_min = hour*6000 + min
41  return tot_min
42 
43 def min2hour(tot_min):
44  h = tot_min//6000
45  day = h//24
46  hour = h - day*24
47  min = tot_min - h*6000
48  return day, hour, min
49 
50 def date2day(year, month, day):
51  day_of_year = date(year, month, day).timetuple().tm_yday
52  return day_of_year
53 
54 def day2date(year, day_of_year):
55  daystr = '{:03}'.format(day_of_year)
56  dt = datetime.strptime(str(year)+"-"+daystr,"%Y-%j")
57  return dt.year, dt.month, dt.day
58 
59 def getDtFilename(l1b_name):
60  DtFilename = l1b_name.replace("L1B", "L2.AER_DT")
61  return DtFilename
62 
63 def getDbFilename(l1b_name):
64  DbFilename = l1b_name.replace("L1B", "L2.AER_DB")
65  return DbFilename
66 
67 
70 
71 def main():
72 
73  args = sys.argv
74 
75  description = '''Download L1A files in specified date-time range.'''
76  usage = "usage: get_viirs_l1a.py -b [start date-time] -e [end date-time] -o [output directory]"
77  version = "v1"
78 
79  parser = optparse.OptionParser(description=description,usage=usage,version=version)
80 
81  # Mandatory arguments
82  mandatoryGroup = optparse.OptionGroup(parser, "Mandatory Arguments",
83  "At a minimum these arguments must be specified")
84 
85  parser.add_option_group(mandatoryGroup)
86 
87  mandatoryGroup.add_option('-b','--begin',
88  action="store",
89  dest="begin" ,
90  type="string",
91  help="Begin date-time")
92 
93  mandatoryGroup.add_option('-e','--end',
94  action="store",
95  dest="end" ,
96  type="string",
97  help="End date-time")
98 
99  mandatoryGroup.add_option('-z','--platform',
100  action="store",
101  dest="platform" ,
102  type="string",
103  help="VIIRS Platform (snpp, jpss1 or jpss2")
104 
105  mandatoryGroup.add_option('-d','--alg',
106  action="store",
107  dest="alg" ,
108  type="string",
109  help="Dark Target (dt) or Deep Blue (db)")
110 
111  mandatoryGroup.add_option('--l1_par',
112  action="store",
113  dest="l1_par" ,
114  type="string",
115  help="The full path of the L1 PCF")
116 
117  mandatoryGroup.add_option('--l2_par',
118  action="store",
119  dest="l2_par" ,
120  type="string",
121  help="The full path of the L2 PCF")
122 
123  # Optional arguments
124  optionalGroup = optparse.OptionGroup(parser, "Extra Options",
125  "These options may be used to customize behavior of this program.")
126 
127  optionalGroup.add_option('--bowtie',
128  action="store_true",
129  dest="bowtie" ,
130  default=False,
131  help="Remove bowtie fill values (default no)")
132 
133  optionalGroup.add_option('--geo',
134  action="store_true",
135  dest="geo" ,
136  default=False,
137  help="Write geolocation group (default no)")
138 
139  optionalGroup.add_option('--anc',
140  action="store_true",
141  dest="anc" ,
142  default=False,
143  help="Write ancillary group (default no)")
144 
145  optionalGroup.add_option('--obs',
146  action="store_true",
147  dest="obs" ,
148  default=False,
149  help="Write observations group (default no)")
150 
151  optionalGroup.add_option('--stats',
152  action="store_true",
153  dest="stats" ,
154  default=False,
155  help="Write statistics group (default no)")
156 
157  optionalGroup.add_option('--glint',
158  action="store_true",
159  dest="glint" ,
160  default=False,
161  help="Do not mask glint (default no)")
162 
163  optionalGroup.add_option('--cloud',
164  action="store_true",
165  dest="cloud" ,
166  default=False,
167  help="Do not mask clouds (default no)")
168 
169  optionalGroup.add_option('--float',
170  action="store_true",
171  dest="float" ,
172  default=False,
173  help="Floating point rather than short integer format (default no)")
174 
175  optionalGroup.add_option('-o','--output_path',
176  action="store",
177  dest="odir" ,
178  type="string",
179  help="The full path of the target directory for L1A files")
180 
181  parser.add_option('-v', '--verbose',
182  dest='verbosity',
183  action="count",
184  default=0,
185  help='each occurrence increases verbosity 1 level from ERROR: -v=WARNING -vv=INFO -vvv=DEBUG')
186 
187  parser.add_option_group(optionalGroup)
188 
189  # Parse the arguments from the command line
190  (options, args) = parser.parse_args()
191 
192  # Set up the logging levels
193  levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG]
194  logging.basicConfig(level = levels[options.verbosity])
195 
196  # Check that all of the mandatory options are given. If one or more
197  # are missing, print error message and exit...
198  mandatories = []
199  mand_errors = []
200  isMissingMand = False
201  for m,m_err in zip(mandatories,mand_errors):
202  if not options.__dict__[m]:
203  isMissingMand = True
204  print (m_err)
205  if isMissingMand :
206  parser.error("Incomplete mandatory arguments, aborting...")
207 
208  # Check that the output directory actually exist
209  options.outputPath = os.path.expanduser(options.odir)
210 
211  # Check that we don't have mutually exclusive options
212 
213  LOG.info('Downloading L1A in %s' % (options.odir) )
214 
215  if not options.outputPath:
216  dir = "L1B_" + datetime.now().isoformat()
217  o_path = os.getcwd() + dir
218  os.mkdir(o_path)
219  elif os.path.isdir(options.outputPath):
220  o_path = options.outputPath
221  elif os.path.isdir(os.path.dirname(options.outputPath)):
222  o_path = options.outputPath
223  os.mkdir(o_path)
224  else:
225  print ("Output path invalid")
226  return
227 
228  str_l1a_dir = o_path + "/l1a/"
229  if not os.path.isdir(str_l1a_dir):
230  os.mkdir(str_l1a_dir)
231  str_l1b_dir = o_path + "/l1b/"
232  if not os.path.isdir(str_l1b_dir):
233  os.mkdir(str_l1b_dir)
234  str_geo_dir = o_path + "/geo/"
235  if not os.path.isdir(str_geo_dir):
236  os.mkdir(str_geo_dir)
237  str_dt_dir = o_path + "/dt/"
238  if not os.path.isdir(str_dt_dir):
239  os.mkdir(str_dt_dir)
240  str_db_dir = o_path + "/db/"
241  if not os.path.isdir(str_db_dir):
242  os.mkdir(str_db_dir)
243  str_anc_dir = o_path + "/anc/"
244  if not os.path.isdir(str_anc_dir):
245  os.mkdir(str_anc_dir)
246 
247  # Download L1A files
248 
249  byear = int(options.begin[0:4])
250  bday = int(options.begin[4:7])
251  bhour = int(options.begin[7:9])
252  bmin = ((int(options.begin[9:13]) + 599)//600) * 600
253  btmin = hour2min(bhour, bmin)
254  eyear = int(options.end[0:4])
255  eday = int(options.end[4:7])
256  ehour = int(options.end[7:9])
257  emin = (int(options.end[9:13])//600) * 600
258  etmin = hour2min(ehour, emin)
259 
260  str_platform = ".nc"
261  if options.platform == "snpp":
262  str_platform = ".L1A_SNPP.nc"
263  elif options.platform == "jpss1":
264  str_platform = ".L1A_JPSS1.nc"
265  elif options.platform == "jpss2":
266  str_platform = ".L1A_JPSS2.nc"
267 
268  algs = []
269  if options.alg == "darktarget":
270  algs = ["darktarget"]
271  elif options.alg == "deepblue":
272  algs = ["deepblue"]
273  elif options.alg == "all":
274  algs = ["darktarget", "deepblue"]
275  else:
276  print ("No algorithm specified. Exiting ...")
277  return
278 
279  if byear != eyear:
280  print ("Beginning and end years must be the same. Exiting ...")
281  return
282  elif eday >= bday:
283  t = btmin
284  t24 = hour2min(24,0)
285  tal = etmin + t24*(eday - bday)
286  while t < tal:
287 # get l1a
288  d, h, s = min2hour(t)
289  str_date_time = "%04d%03d%02d%04d" % (byear, bday+d, h, s)
290  str_l1a_name = "V" + str_date_time + str_platform
291  print ("Processing: " + str_l1a_name)
292  sfl1a = str_l1a_dir + str_l1a_name
293  l1a_files = init_dir( str_l1a_dir )
294  l1a_file = vf.l1_file(sfl1a)
295  str_geo_name = l1a_file.getGeoMFilename()
296  gmod = str_geo_dir + str_geo_name
297  geo_files = init_dir( str_geo_dir )
298  lmod = str_l1b_dir + l1a_file.getModFilename()
299  l1b_files = init_dir( str_l1b_dir )
300  if (not sfl1a in l1a_files) and (not lmod in l1b_files):
301  srpath = str_url + str_l1a_name
302  command = str_wget + str_wdir + str_l1a_dir + " " + srpath
303  print (command)
304  result = os.system(command)
305 # get gdas1 if necessary
306  year, month, day = day2date(byear, bday+d)
307  str_date_hour = "%04d%02d%02dT%02d%04d" % (byear, month, day, h, 0)
308  str_anc_name = "GMAO_MERRA2." + str_date_hour + ".MET.nc"
309  gdas1 = str_anc_dir + str_anc_name
310  anc_files = init_dir( str_anc_dir )
311  if not gdas1 in anc_files:
312  arpath = str_url + str_anc_name
313  command = str_wget + str_wdir + str_anc_dir + " " + arpath
314  print (command)
315  result = os.system(command)
316 # get gdas2 if necessary
317  if (h==23):
318  year, month, day = day2date(byear, bday+d+1)
319  str_date_hour = "%04d%02d%02dT%02d%04d" % (byear, month, day, 0, 0)
320  else:
321  str_date_hour = "%04d%02d%02dT%02d%04d" % (byear, month, day, h+1, 0)
322  str_anc_name = "GMAO_MERRA2." + str_date_hour + ".MET.nc"
323  gdas2 = str_anc_dir + str_anc_name
324  if not gdas2 in anc_files:
325  arpath = str_url + str_anc_name
326  command = str_wget + str_wdir + str_anc_dir + " " + arpath
327  print (command)
328  result = os.system(command)
329 # geolocate
330  if not gmod in geo_files:
331  grpath = str_url + str_geo_name
332  command = str_wget + str_wdir + str_geo_dir + " " + grpath
333  print (command)
334  result = os.system(command)
335  print ("geo file: " + gmod)
336 # calibrate
337  if not lmod in l1b_files:
338  command = "calibrate_viirs " + options.l1_par + " ifile=" + sfl1a + " l1bfile_mod=" + lmod
339  print (command)
340  result = os.system(command)
341  print ("l1b file: " + lmod)
342 # resample to fill bowtie pixels
343  if options.bowtie:
344  cgmod = "geo_resam_" + datetime.now().strftime("%f") + ".nc"
345  command = "cp " + gmod + " " + cgmod
346  result = os.system(command)
347  clmod = "l1b_resam_" + datetime.now().strftime("%f") + ".nc"
348  command = "cp " + lmod + " " + clmod
349  result = os.system(command)
350  command = "resam_viirs " + "ifile=" + clmod + " geofile=" + cgmod
351  print ("Resampling granule to fill bowtie regions")
352  result = os.system(command)
353  else:
354  cgmod = gmod
355  clmod = lmod
356 
357 # run the aerosol detection algorithms
358  for alg in algs:
359  if alg == "deepblue":
360  alg_str = "deepblue "
361  opath = str_db_dir + l1a_file.getDbFilename()
362  else:
363  alg_str = "darktarget "
364  opath = str_dt_dir + l1a_file.getDtFilename()
365  l2par = " par=" + options.l2_par
366  ialg = " alg=" + alg_str
367  il1b = " ifile=" + clmod
368  igeo = " geofile=" + cgmod
369  ianc1 = " gdas1=" + gdas1
370  ianc2 = " gdas2=" + gdas2
371  opth = " ofile=" + opath
372  ogeo = " geolocation" if options.geo else ""
373  oanc = " ancillary" if options.anc else ""
374  oobs = " observations" if options.obs else ""
375  ostat = " statistics" if options.stats else ""
376  oglnt = " mask_glint=off" if options.glint else ""
377  ocld = " mask_cloud=off" if options.cloud else ""
378  oflt= " short_format=off" if options.float else ""
379  lprw = " lines_per_rw=10"
380  command = "dtdb " + l2par + ialg + il1b + igeo + ianc1 + ianc2 + opth + ogeo + oanc + oobs + ostat + oglnt + ocld + oflt + lprw
381  print(command)
382  result = os.system(command)
383 # command = "rm " + cgmod + " " + clmod
384  result = os.system(command)
385 
386  t += 600
387 
388  else:
389  print ("Invalid start and end dates specified. Exiting ...")
390  return
391 
392  print ("All L1A files in range processed")
393 
394  LOG.info('Exiting...')
395  return 0
396 
397 if __name__=='__main__':
398  sys.exit(main())
399 
def min2hour(tot_min)
def main()
Main Function #.
def day2date(year, day_of_year)
const char * str
Definition: l1c_msi.cpp:35
def date2day(year, month, day)
def init_dir(inpath)
def getDtFilename(l1b_name)
def getDbFilename(l1b_name)
def hour2min(hour, min)