OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
modis_utils.py
Go to the documentation of this file.
1 """
2 Utility functions for MODIS processing programs.
3 """
4 
5 import os
6 import re
7 import shutil
8 import subprocess
9 import sys
10 
11 from seadasutils.MetaUtils import readMetadata
13 import mlp.obpg_data_file
15 import seadasutils.ProcUtils as ProcUtils
16 
17 def buildpcf(self):
18  """
19  Build process control file for MODIS L1A, Geolocation and L1B creation
20  """
21 
22  base = self.filename
23  if self.proctype == "modisL1A":
24  base = self.l1a
25  if self.proctype == 'modisGEO':
26  base = self.geofile
27  if self.proctype == 'modisL1B':
28  base = self.okm
29  self.pcf_file = base + '.pcf'
30 
31  os.environ['PGS_PC_INFO_FILE'] = self.pcf_file
32  if self.proctype == "modisGEO":
33  if self.entrained:
34  self.kinematic_state = "MODIS Packet"
35  if self.verbose:
36  print("Using entrained attitude/ephemeris information")
37 
38  pcf = [line for line in open(self.pcf_template, 'r')]
39 
40  sed = open(self.pcf_file, 'w')
41  for line in pcf:
42  if self.proctype == "modisL1A":
43  line = line.replace('L0DIR', self.dirs['run'].resolve().as_posix())
44  line = line.replace('CURRL0GRAN0',
45  '.'.join([self.l0file, 'constr']))
46  line = line.replace('CURRL0GRAN1', self.l0file)
47  line = line.replace('L1ADIR', self.dirs['run'].resolve().as_posix())
48  line = line.replace('L1AFILE', os.path.basename(self.l1a))
49  line = line.replace('MCFDIR', self.dirs['mcf'])
50  line = line.replace('L1A_MCF', self.l1amcf)
51  line = line.replace('CALDIR', self.dirs['cal'])
52  line = line.replace('ENGLUTFILE', self.englutfile)
53  line = line.replace('ENGLUTVER', self.englutver)
54  line = line.replace('STARTTIME', self.start)
55  line = line.replace('STOPTIME', self.stop)
56  line = line.replace('GRANMIN', self.granmin)
57  # since no previous granule, delete PREVL0GRAN0 lines from PCF file
58  if '599001' in line:
59  continue
60 
61  if self.proctype == "modisGEO":
62  line = line.replace("MCFDIR", self.dirs['mcf'])
63  line = line.replace("L1A_MCF", self.l1amcf)
64  line = line.replace("GEO_MCF", self.geomcf)
65  line = line.replace("GEOLUTFILE", self.geolutfile)
66  line = line.replace("GEOLUTVER", self.geolutver)
67  line = line.replace("GEOMVRFILE", self.geomvrfile)
68  line = line.replace("GEOMVRVER", self.geomvrver)
69  line = line.replace("GEOMVRLIST", '')
70  line = line.replace("PLANETFILE", self.planetfile)
71  line = line.replace("KINEMATIC_STATE", self.kinematic_state)
72  line = line.replace("DEMDIR", self.dirs['dem'])
73 
74  if self.terrain:
75  line = line.replace("TERRAIN_CORRECT", "TRUE")
76  else:
77  line = line.replace("TERRAIN_CORRECT", "FALSE")
78 
79  if self.entrained:
80  if "ATTDIR" in line:
81  continue
82 
83  if "EPHDIR" in line:
84  continue
85  else:
86  if "ATTDIR" in line:
87  if self.attdir1 == 'NULL' and re.search('1$', line):
88  continue
89  if self.attdir2 == "NULL" and re.search('2$', line):
90  continue
91  if self.attdir3 == "NULL" and re.search('3$', line):
92  continue
93 
94  if "EPHDIR" in line:
95  if self.ephdir1 == 'NULL' and re.search('1$', line):
96  continue
97  if self.ephdir2 == "NULL" and re.search('2$', line):
98  continue
99  if self.ephdir3 == "NULL" and re.search('3$', line):
100  continue
101 
102  line = line.replace("ATTDIR1", self.attdir1)
103  line = line.replace("ATTDIR2", self.attdir2)
104  line = line.replace("ATTDIR3", self.attdir3)
105  line = line.replace("ATTFILE1", self.attfile1)
106  line = line.replace("ATTFILE2", self.attfile2)
107  line = line.replace("ATTFILE3", self.attfile3)
108  line = line.replace("EPHDIR1", self.ephdir1)
109  line = line.replace("EPHDIR2", self.ephdir2)
110  line = line.replace("EPHDIR3", self.ephdir3)
111  line = line.replace("EPHFILE1", self.ephfile1)
112  line = line.replace("EPHFILE2", self.ephfile2)
113  line = line.replace("EPHFILE3", self.ephfile3)
114 
115  if self.proctype == "modisL1B":
116  line = line.replace('L1BDIR', self.dirs['run'].resolve().as_posix())
117  line = line.replace('QKMFILE', os.path.basename(self.qkm))
118  line = line.replace('1KMFILE', os.path.basename(self.okm))
119  line = line.replace('HKMFILE', os.path.basename(self.hkm))
120  line = line.replace('OBCFILE', os.path.basename(self.obc))
121  line = line.replace('QKM_MCF', os.path.basename(self.qkm_mcf))
122  line = line.replace('HKM_MCF', os.path.basename(self.hkm_mcf))
123  line = line.replace('1KM_MCF', os.path.basename(self.okm_mcf))
124  line = line.replace('OBC_MCF', os.path.basename(self.obc_mcf))
125  line = line.replace('CALDIR', self.dirs['cal'])
126  line = line.replace('REFL_LUT', self.refl_lut)
127  line = line.replace('EMIS_LUT', self.emis_lut)
128  line = line.replace('QA_LUT', self.qa_lut)
129  line = line.replace('LUTVERSION', self.lutversion)
130 
131  if re.search('(GEO|L1B)', self.proctype):
132  line = line.replace("GEODIR",
133  os.path.abspath(os.path.dirname(self.geofile)))
134  line = line.replace("GEOFILE", os.path.basename(self.geofile))
135 
136  line = line.replace('MCFDIR', self.dirs['mcf'])
137  line = line.replace("CALDIR", self.dirs['cal'])
138  line = line.replace("STATIC", self.dirs['static'])
139  line = line.replace("L1ADIR",
140  os.path.abspath(os.path.dirname(self.filename)))
141  line = line.replace("L1AFILE", os.path.basename(self.filename))
142 
143  line = line.replace("VARDIR", os.path.join(self.dirs['var'], 'modis'))
144  line = line.replace('LOGDIR', self.dirs['run'].resolve().as_posix())
145  line = line.replace('SAT_INST', self.sat_inst)
146  line = line.replace('PGEVERSION', self.pgeversion)
147 
148  sed.write(line)
149  sed.close()
150 
151 
153  """
154  Determine the start time, stop time, and platform of a MODIS hdf4 file.
155  """
156 
157  meta = readMetadata(arg)
158  sat_name = meta['ASSOCIATEDPLATFORMSHORTNAME'].lower()
159  start_time = meta['RANGEBEGINNINGDATE'] + 'T' + meta['RANGEBEGINNINGTIME'][0:8]
160  end_time = meta['RANGEENDINGDATE'] + 'T' + meta['RANGEENDINGTIME'][0:8]
161  # at this point datetimes are formatted as YYYY-MM-DD HH:MM:SS.uuuuuu
162 
163  # return values formatted as YYYYDDDHHMMSS
164  # return (ProcUtils.date_convert(start_time, 'h', 'j'),
165  # ProcUtils.date_convert(end_time, 'h', 'j'),
166  # sat_name)
167  return (start_time,
168  end_time,
169  sat_name)
170 
171 
172 def getversion(file_name):
173  """
174  Returns the version of the file named filename.
175  """
176  clean = ""
177  if os.path.exists(file_name):
178  for line in open(file_name):
179  if "$Revision" in line:
180  sidx = line.find('$Revision')
181  eidx = line.rfind('$')
182  clean = line[sidx + 10:eidx - 1].lstrip()
183  break
184 
185  return clean
186 
187 
188 def sortLUT(lut, length):
189  """
190  Version comparison for LUTs
191  """
192  lut = lut.split("\n")
193  for ndx in range(len(lut)):
194  lut[ndx] = lut[ndx][length:].rstrip('.hdf')
195 
196  lut = sorted(lut, cmp=cmpver)
197  return lut[0]
198 
199 
200 def cmpver(a, b):
201  """
202  Version comparison algorithm
203  """
204 
205  def fixup(i):
206  """
207  Returns i as an int if possible, or in its original form otherwise.
208  """
209  try:
210  return int(i)
211  except ValueError:
212  return i
213 
214  a = list(map(fixup, re.findall(r'\d+|\w+', a)))
215  b = list(map(fixup, re.findall(r'\d+|\w+', b)))
216  return cmp(b, a)
217 
218 
219 def cleanup(lut):
220  clean = ""
221  for ndx in range(len(lut)):
222  if ndx % 2:
223  clean = clean + lut[ndx] + "\n"
224  return clean
225 
226 
227 def modis_env(self):
228  """
229  Set up the MODIS processing environment
230  """
231 
232  if not os.path.exists(os.path.join(os.getenv("OCDATAROOT"), "modis")):
233  print("ERROR: The " + os.path.join(os.getenv("OCDATAROOT"), "modis") + "directory does not exist.")
234  sys.exit(1)
235 
236  os.environ["PGSMSG"] = os.path.join(os.getenv("OCDATAROOT"),
237  "modis", "static")
238 
239  # MODIS L1A
240  if self.proctype == "modisL1A":
241  aqua = re.compile(r'''(
242  ^[aA]| # [Aa]*
243  ^MOD00.P| # MOD00.P*
244  ^MYD\S+.A| # MYD*.A*
245  ^P1540064 # P1540064*
246  )''', re.VERBOSE)
247  terra = re.compile(r'''(
248  ^[tT]| # [tT]*
249  ^MOD\S+.A| # MOD*.A*
250  ^P0420064 # P0420064*
251  )''', re.VERBOSE)
252 
253  if self.sat_name is not None:
254  if aqua.search(self.sat_name) is not None:
255  self.sat_name = 'aqua'
256  elif terra.search(self.sat_name) is not None:
257  self.sat_name = 'terra'
258  else:
259  if aqua.search(os.path.basename(self.filename)) is not None:
260  self.sat_name = 'aqua'
261  elif terra.search(os.path.basename(self.filename)) is not None:
262  self.sat_name = 'terra'
263  else:
264  print("ERROR: Unable to determine platform type for " + self.filename)
265  print("")
266  print("Please use the '--satellite' argument to specify the platform as 'aqua' or 'terra',")
267  print("or rename your input file to match one of the following formats:")
268  print("")
269  print("\tAqua: 'a*' or 'A*' or 'MOD00.P*' or 'P1540064* or 'MYD*.A*''")
270  print("\tTerra: 't*' or 'T*' or 'MOD00.A*' or 'P0420064*'")
271  sys.exit(1)
272  else:
273  # Determine pass start time and platform
274  self.start, self.stop, self.sat_name = modis_timestamp(self.filename)
275 
276  # set sensor specific variables
277  if self.sat_name == 'aqua':
278  self.sensor = 'modisa'
279  self.sat_inst = 'PM1M'
280  self.prefix = 'MYD'
281  if self.proctype == 'modisL1B':
282  self.pgeversion = "6.2.1_obpg"
283  elif self.sat_name == 'terra':
284  self.sensor = 'modist'
285  self.sat_inst = 'AM1M'
286  self.prefix = 'MOD'
287  if self.proctype == 'modisL1B':
288  self.pgeversion = "6.2.2_obpg"
289 
290  else:
291  print("ERROR: Unable to determine platform type for", self.filename)
292  sys.exit(1)
293 
294  # Static input directories
295  self.dirs['cal'] = os.path.join(os.getenv("OCDATAROOT"), 'modis', self.sat_name, 'cal')
296  self.dirs['mcf'] = os.path.join(os.getenv("OCDATAROOT"), 'modis', self.sat_name, 'mcf')
297  self.dirs['static'] = os.path.join(os.getenv("OCDATAROOT"), 'modis', 'static')
298  self.dirs['dem'] = os.path.join(os.getenv("OCDATAROOT"), 'modis', 'dem')
299  if not os.path.exists(self.dirs['dem']):
300  self.dirs['dem'] = self.dirs['static']
301  self.dirs['pcf'] = os.path.join(os.getenv("OCDATAROOT"), 'modis', 'pcf')
302 
303  # MODIS L1A
304  if self.proctype == "modisL1A":
305  self.pcf_template = os.path.join(self.dirs['pcf'], 'L1A_template.pcf')
306  if not os.path.exists(self.pcf_template):
307  print("ERROR: Could not find the L1A PCF template: " + self.pcf_template)
308  sys.exit(1)
309 
310  self.l1amcf = ''.join([self.prefix, '01_', self.collection_id, '.mcf'])
311  self.englutfile = 'ENG_DATA_LIST_' + self.sat_name.upper() + '_V' + self.pgeversion
312  if self.lutversion:
313  self.englutfile += '.' + self.lutversion
314  self.englutver = getversion(os.path.join(self.dirs['cal'],
315  self.englutfile))
316 
317  # MODIS GEO
318  if self.proctype == "modisGEO":
319  self.pcf_template = os.path.join(self.dirs['pcf'], 'GEO_template.pcf')
320  if not os.path.exists(self.pcf_template):
321  print("ERROR: Could not find GEO PCF template " + self.pcf_template)
322  sys.exit(1)
323 
324  self.l1amcf = ''.join([self.prefix, '01_', self.collection_id, '.mcf'])
325  self.geomcf = ''.join([self.prefix, '03_', self.collection_id, '.mcf'])
326  self.geolutfile = ''.join([self.prefix, '03LUT.coeff_V', self.pgeversion])
327  self.geomvrfile = ''.join(['maneuver_', self.sat_name, '.coeff_V', self.pgeversion])
328  if self.lutversion:
329  self.geolutfile += '.' + self.lutversion
330  self.geomvrfile += '.' + self.lutversion
331  self.geolutver = getversion(os.path.join(self.dirs['cal'],
332  self.geolutfile))
333  self.geomvrver = getversion(os.path.join(self.dirs['cal'],
334  self.geomvrfile))
335 
336  self.planetfile = "de200.eos"
337  if not os.path.exists(os.path.join(self.dirs['static'],
338  self.planetfile)):
339  if not os.path.exists(os.path.join(self.dirs['static'],
340  'de200.dat')):
341  print("ERROR: File " + os.path.join(self.dirs['static'], self.planetfile) + "does not exist.")
342  print(" nor does " + os.path.join(self.dirs['static'], 'de200.dat') + "...")
343  print(" Something is amiss with the environment...")
344  sys.exit(1)
345  else:
346  if self.verbose:
347  print("Creating binary planetary ephemeris file...")
348  planetfile = os.path.join(self.dirs['static'], 'de200.dat')
349  cmd = [os.path.join(self.dirs['bin3'], 'ephtobin'), planetfile]
350  status = subprocess.run(cmd, shell=False).returncode
351 
352  if status:
353  print(status)
354  print("Error creating binary planetary ephemeris file")
355  sys.exit(1)
356  else:
357  shutil.move('de200.eos', os.path.join(self.dirs['static'],
358  'de200.eos'))
359 
360  # determine output file name
361  if not self.geofile:
362  file_typer = mlp.get_obpg_file_type.ObpgFileTyper(self.filename)
363  ftype, sensor = file_typer.get_file_type()
364  stime, etime = file_typer.get_file_times()
365  data_files_list = list([mlp.obpg_data_file.ObpgDataFile(self.filename,
366  ftype, sensor,
367  stime, etime)])
368  self.geofile = mlp.get_output_name_utils.get_output_name(data_files_list, 'geo', None)
369 
370  # MODIS L1B
371  if self.proctype == "modisL1B":
372  self.pcf_template = os.path.join(self.dirs['pcf'], 'L1B_template.pcf')
373  if not os.path.exists(self.pcf_template):
374  print("ERROR: Could not find the L1B PCF template", self.pcf_template)
375  sys.exit(1)
376 
377  # Search LUTDIR for lut names
378  if not self.lutdir:
379  self.lutdir = os.path.join(self.dirs['var'], self.sensor, 'cal', 'OPER')
380 
381  if not self.lutversion:
382  try:
383  from seadasutils.LutUtils import lut_version
384  versions = [lut_version(f) for f in os.listdir(self.lutdir) if f.endswith('.hdf')]
385  self.lutversion = sorted(versions)[-1][1:] # highest version number
386  except:
387  print("ERROR: Could not find LUTs in", self.lutdir)
388  sys.exit(1)
389 
390  self.refl_lut = self.prefix + '02_Reflective_LUTs.V' + self.lutversion + '.hdf'
391  self.emis_lut = self.prefix + '02_Emissive_LUTs.V' + self.lutversion + '.hdf'
392  self.qa_lut = self.prefix + '02_QA_LUTs.V' + self.lutversion + '.hdf'
393 
394  if self.verbose:
395  print("")
396  print("LUT directory: %s" % self.lutdir)
397  print("LUT version: %s" % self.lutversion)
398  print("Reflective LUT: %s" % self.refl_lut)
399  print("Emissive LUT: %s" % self.emis_lut)
400  print("QA LUT: %s" % self.qa_lut)
401  print("")
402 
403  self.qkm_mcf = ''.join([self.prefix, '02QKM_',
404  self.collection_id, '.mcf'])
405  self.hkm_mcf = ''.join([self.prefix, '02HKM_',
406  self.collection_id, '.mcf'])
407  self.okm_mcf = ''.join([self.prefix, '021KM_',
408  self.collection_id, '.mcf'])
409  self.obc_mcf = ''.join([self.prefix, '02OBC_',
410  self.collection_id, '.mcf'])
411 
412  # set output file name
413  file_typer = mlp.get_obpg_file_type.ObpgFileTyper(self.filename)
414  ftype, sensor = file_typer.get_file_type()
415  stime, etime = file_typer.get_file_times()
416  data_files_list = list([mlp.obpg_data_file.ObpgDataFile(self.filename,
417  ftype, sensor,
418  stime, etime)])
419  l1b_name= mlp.get_output_name_utils.get_output_name(data_files_list, 'modis_L1B', None)
420  self.base = os.path.join(self.dirs['run'],
421  os.path.basename(l1b_name).split('.')[0])
422 
423  if self.okm is None:
424  if re.search('MODIS', l1b_name):
425  self.okm = l1b_name
426  elif re.search('L1A_LAC', self.filename):
427  self.okm = self.filename.replace("L1A_LAC", "L1B_LAC")
428  else:
429  self.okm = '.'.join([self.base, 'L1B_LAC'])
430  if self.hkm is None:
431  if re.search('MODIS', l1b_name):
432  self.hkm = l1b_name.replace("MODIS", "MODIS_HKM")
433  elif re.search('L1A_LAC', self.filename):
434  self.hkm = self.filename.replace("L1A_LAC", "L1B_HKM")
435  else:
436  self.hkm = '.'.join([self.base, 'L1B_HKM'])
437  if self.qkm is None:
438  if re.search('MODIS', l1b_name):
439  self.qkm = l1b_name.replace("MODIS", "MODIS_QKM")
440  elif re.search('L1A_LAC', self.filename):
441  self.qkm = self.filename.replace("L1A_LAC", "L1B_QKM")
442  else:
443  self.qkm = '.'.join([self.base, 'L1B_QKM'])
444  if self.obc is None:
445  if re.search('MODIS', l1b_name):
446  self.obc = l1b_name.replace("MODIS", "MODIS_OBC")
447  elif re.search('L1A_LAC', self.filename):
448  self.obc = self.filename.replace("L1A_LAC", "L1B_OBC")
449  else:
450  self.obc = '.'.join([self.base, 'L1B_OBC'])
451 
452  if not os.path.exists(os.path.join(self.lutdir, self.refl_lut)) \
453  or not os.path.exists(os.path.join(self.lutdir, self.emis_lut)) \
454  or not os.path.exists(os.path.join(self.lutdir, self.qa_lut)):
455  print("ERROR: One or more of the required LUTs does not exist in %s:" % self.lutdir)
456  print("")
457  print("Reflective LUT:", self.refl_lut)
458  print("Emissive LUT:", self.emis_lut)
459  print("QA LUT:", self.qa_lut)
460  sys.exit(1)
461 
462  self.dirs['rlut'] = os.path.abspath(os.path.dirname(self.refl_lut))
463  self.refl_lut = os.path.basename(self.refl_lut)
464  self.dirs['elut'] = os.path.abspath(os.path.dirname(self.emis_lut))
465  self.emis_lut = os.path.basename(self.emis_lut)
466  self.dirs['qlut'] = os.path.abspath(os.path.dirname(self.qa_lut))
467  self.qa_lut = os.path.basename(self.qa_lut)
468 
469  self.dirs['cal'] = self.lutdir
list(APPEND LIBS ${PGSTK_LIBRARIES}) add_executable(atteph_info_modis atteph_info_modis.c) target_link_libraries(atteph_info_modis $
Definition: CMakeLists.txt:7
def cmpver(a, b)
Definition: modis_utils.py:200
def modis_timestamp(arg)
Definition: modis_utils.py:152
def lut_version(lut_name)
Definition: LutUtils.py:7
def readMetadata(filename)
Definition: MetaUtils.py:201
def modis_env(self)
Definition: modis_utils.py:227
def buildpcf(self)
Definition: modis_utils.py:17
def sortLUT(lut, length)
Definition: modis_utils.py:188
def get_output_name(data_files, target_program, clopts)
def getversion(file_name)
Definition: modis_utils.py:172