4 Program to perform multilevel processing (previously known as the
5 seadas_processor and sometimes referred to as the 'uber' processor).
11 import ConfigParser
as configparser
39 __author__ =
'melliott'
43 Configuration data for the program which needs to be widely available.
46 def __init__(self, hidden_dir, ori_dir, verbose, overwrite, use_existing,
47 deletefiles, out_dir=None):
48 self.
prog_name = os.path.basename(sys.argv[0])
50 if not os.path.exists(hidden_dir):
54 if sys.exc_info()[1].find(
'Permission denied:') != -1:
73 cfg_file_path = os.path.join(self.
hidden_dir,
'seadas_ocssw.cfg')
74 if os.path.exists(cfg_file_path):
79 ProcessorConfig._instance = self
81 def _read_saved_options(self, cfg_path):
83 Gets options stored in the program's configuration file.
86 cfg_parser = configparser.ConfigParser()
87 cfg_parser.read(cfg_path)
90 int(cfg_parser.get(
'main',
93 except configparser.NoSectionError
as nse:
94 print (
'nse: ' +
str(nse))
95 print (
'sys.exc_info(): ')
96 for msg
in sys.exc_info():
97 print (
' ' +
str(msg))
98 log_and_exit(
'Error! Configuration file has no "main" ' +
100 except configparser.NoOptionError:
101 log_and_exit(
'Error! The "main" section of the configuration ' +
102 'file does not specify a "par_file_age".')
103 except configparser.MissingSectionHeaderError:
104 log_and_exit(
'Error! Bad configuration file, no section headers ' +
107 def _set_temp_dir(self):
109 Sets the value of the temporary directory.
111 if os.path.exists(
'/tmp')
and os.path.isdir(
'/tmp')
and \
112 os.access(
'/tmp', os.W_OK):
116 if os.path.exists(cwd)
and os.path.isdir(cwd)
and \
117 os.access(cwd, os.W_OK):
120 log_and_exit(
'Error! Unable to establish a temporary ' +
123 def _write_default_cfg_file(self, cfg_path):
125 Writes out a configuration file using default values.
127 with open(cfg_path,
'wt')
as cfg_file:
128 cfg_file.write(
'[main]\n')
129 cfg_file.write(
'par_file_age=30 # units are days\n')
133 Sensor contains the recipe and procssing method for general sensors.
138 'level 1a': processing_rules.build_rule(
'level 1a', [
'level 0'],
140 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'l1'],
142 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
148 'level 1b': processing_rules.build_rule(
'level 1b', [
'level 1a'],
150 'l2gen': processing_rules.build_rule(
'l2gen', [
'l1'], self.
run_l2gen,
152 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
154 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
156 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
158 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
167 'l2extract',
'l2brsgen',
'l2bin',
'l3bin',
169 self.
name =
'general'
176 Exits with an error message when there is an attempt to process a source
177 file at the lowest level of a rule chain.
179 err_msg =
'Error! Attempting to create {0} product, but no creation program is known.'.format(proc.target_type)
184 Sets up and runs an executable program.
187 prog = os.path.join(proc.ocssw_bin,
'l1bgen_generic')
188 args = [
'ifile={}'.format(proc.input_file),
'ofile={}'.format(proc.output_file)]
189 if not proc.geo_file
is None:
190 args.append(
'geofile={}'.format(proc.geo_file))
199 Runs the l1brsgen executable.
205 prog = os.path.join(proc.ocssw_bin,
'l1brsgen')
209 cmd.extend([
'ifile={}'.format(proc.input_file),
'ofile={}'.format(proc.output_file)])
211 cmd.append(
'geofile={}'.format(proc.geo_file))
214 logging.debug(
'Executing: "%s"',
" ".join(
str(x)
for x
in cmd))
220 Set up for and perform L2 binning.
222 prog = os.path.join(proc.ocssw_bin,
'l2bin')
223 if not os.path.exists(prog):
224 print (
"Error! Cannot find executable needed for {0}".\
225 format(proc.rule_set.rules[proc.target_type].action))
226 args = [
'infile={}'.format(proc.input_file),
227 'ofile={}'.format(proc.output_file)]
234 print (
'l2bin cmd: {}'.format(
" ".join(
str(x)
for x
in cmd)))
237 if os.path.exists(proc.output_file):
238 msg =
'-I- The l2bin program returned a status value of {0}. Proceeding with processing, using the output l2 bin file {1}'.format(ret_val, proc.output_file)
242 msg =
'-I- The l2bin program produced a bin file with no data. No further processing will be done.'
248 Runs the l2brsgen executable.
250 logging.debug(
"In run_l2brsgen")
251 prog = os.path.join(proc.ocssw_bin,
'l2brsgen')
255 cmd.extend([
'ifile={}'.format(proc.input_file),
'ofile={}'.format(proc.output_file)])
256 logging.debug(
'Executing: "%s"',
" ".join(
str(x)
for x
in cmd))
262 Set up and run l2extract.
264 if 'SWlon' in proc.par_data
and 'SWlat' in proc.par_data
and \
265 'NElon' in proc.par_data
and 'NElat' in proc.par_data:
267 if (start_line
is None)
or (end_line
is None)
or (start_pixel
is None) \
268 or (end_pixel
is None):
269 err_msg =
'Error! Could not compute coordinates for l2extract.'
271 l2extract_prog = os.path.join(proc.ocssw_bin,
'l2extract')
272 l2extract_cmd = [l2extract_prog, proc.input_file,
273 str(start_pixel),
str(end_pixel),
274 str(start_line),
str(end_line),
'1',
'1',
276 logging.debug(
'Executing l2extract command: {}'.format(
" ".join(
str(x)
for x
in l2extract_cmd)))
280 err_msg =
'Error! Geographical coordinates not specified for l2extract.'
285 Set up for and perform L2 processing.
289 getanc_cmd = [getanc_prog, proc.input_file]
290 logging.debug(
'running getanc command: {}'.format(
" ".join(
str(x)
for x
in getanc_cmd)))
292 l2gen_prog = os.path.join(proc.ocssw_bin,
'l2gen')
293 if not os.path.exists(l2gen_prog):
294 print (
"Error! Cannot find executable needed for {0}".\
295 format(proc.rule_set.rules[proc.target_type].action))
297 proc.geo_file, proc.output_file)
298 logging.debug(
'L2GEN_FILE=' + proc.output_file)
300 args =
'par={}/{}'.format(cfg_data.original_dir, par_name)
301 l2gen_cmd = [l2gen_prog, args]
302 if cfg_data.verbose
or DEBUG:
303 logging.debug(
'l2gen cmd: {}'.format(
" ".join(
str(x)
for x
in l2gen_cmd)))
308 Set up and run the l3Bin program
310 prog = os.path.join(proc.ocssw_bin,
'l3bin')
311 if not os.path.exists(prog):
312 print (
"Error! Cannot find executable needed for {0}".\
313 format(proc.rule_set.rules[proc.target_type].action))
314 args = [
'ifile={}'.format(proc.input_file)]
315 for key
in proc.par_data:
316 if (key !=
'odir')
and (key !=
'ofile')
and not key.lower()
in FILE_USE_OPTS:
317 args.append(
"{}={}".format(key,proc.par_data[key]))
318 args.append(
"in={}".format(proc.input_file))
319 args.append(
"out={}".format(proc.output_file))
323 logging.debug(
'Executing l3bin command: {}'.format(
" ".join(
str(x)
for x
in cmd)))
326 if os.path.exists(proc.output_file):
327 msg =
'-I- The l3bin program returned a status value of {0}. Proceeding with processing, using the output l2 bin file {1}'.format(
328 ret_val, proc.output_file)
332 msg =
"-I- The l3bin program produced a bin file with no data. No further processing will be done."
338 Set up and run the l3mapgen program.
340 prog = os.path.join(proc.ocssw_bin,
'l3mapgen')
341 if not os.path.exists(prog):
342 print (
"Error! Cannot find executable needed for {0}".\
343 format(proc.rule_set.rules[proc.target_type].action))
344 args = [
'ifile={}'.format(proc.input_file)]
345 for key
in proc.par_data:
346 if (key !=
'odir')
and (key !=
'ofile')
and not key.lower()
in FILE_USE_OPTS:
347 args.append(
'{}={}'.format(key, proc.par_data[key]))
348 args.append(
'ofile={}'.format(proc.output_file))
352 logging.debug(
'Executing l3mapgen command: "%s"',
" ".join(
str(x)
for x
in cmd))
380 Sensor GOCI contains GOCI specific recipe and procssing methods.
385 'level 1a': processing_rules.build_rule(
'level 1a', [
'level 0'],
387 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'l1'],
389 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
395 'level 1b': processing_rules.build_rule(
'level 1b', [
'level 1a'],
397 'l2gen': processing_rules.build_rule(
'l2gen', [
'level 1b'], self.
run_l2gen,
399 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
401 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
403 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
405 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
414 'l2extract',
'l2brsgen',
'l2bin',
'l3bin',
422 Sensor HAWKEYE contains HAWKEYE specific recipe and procssing methods.
427 'level 1a': processing_rules.build_rule(
'level 1a', [
'nothing lower'],
429 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'level 1a',
'geo'],
433 'geo': processing_rules.build_rule(
'geo', [
'level 1a'],
435 'l2gen': processing_rules.build_rule(
'l2gen', [
'level 1a',
'geo'],
437 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
439 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
443 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
445 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
447 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
456 'l2gen',
'l2extract',
'l2bin',
457 'l2brsgen',
'l3bin',
'l3mapgen']
464 Set up and run the geolocate_hawkeye program, returning the exit status of the run.
466 logging.debug(
'In run_geolocate_hawkeye')
472 err_msg =
'Error! Cannot find program geolocate_hawkeye.'
473 logging.info(err_msg)
475 args = [proc.input_file, proc.output_file]
480 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
485 Sensor MERIS contains MERIS specific recipe and processing methods.
488 target type (string), source types (list of strings), batch processing
489 flag (Boolean), action to take (function name)
494 'level 1a': processing_rules.build_rule(
'level 1a', [
'level 0'],
496 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'l1'],
498 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
504 'level 1b': processing_rules.build_rule(
'level 1b', [
'level 1a'],
506 'l2gen': processing_rules.build_rule(
'l2gen', [
'level 1b'], self.
run_l2gen,
508 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
510 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
512 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
514 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
523 'l2extract',
'l2brsgen',
'l2bin',
'l3bin',
531 Sensor MODIS contains MODIS specific recipe and processing methods.
536 'level 0': processing_rules.build_rule(
'level 0', [
'nothing lower'],
538 'level 1a': processing_rules.build_rule(
'level 1a', [
'level 0'],
540 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'level 1b',
'geo'],
544 'geo': processing_rules.build_rule(
'geo', [
'level 1a'], self.
run_geo,
546 'l1aextract': processing_rules.build_rule(
'l1aextract',
550 'level 1b': processing_rules.build_rule(
'level 1b',
553 'l2gen': processing_rules.build_rule(
'l2gen', [
'level 1b',
'geo'],
555 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
557 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
561 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
563 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
565 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
575 'level 1b',
'l1brsgen',
'l2gen',
'l2extract',
576 'l2bin',
'l2brsgen',
'l3bin',
'l3mapgen']
583 Set up and run l1aextract_modis.
585 if 'SWlon' in proc.par_data
and 'SWlat' in proc.par_data
and\
586 'NElon' in proc.par_data
and 'NElat' in proc.par_data:
588 if (start_line
is None)
or (end_line
is None)
or (start_pixel
is None)\
589 or (end_pixel
is None):
590 err_msg =
'Error! Cannot find l1aextract_modis coordinates.'
592 l1aextract_prog = os.path.join(proc.ocssw_bin,
'l1aextract_modis')
593 l1aextract_cmd = [l1aextract_prog, proc.input_file,
594 str(start_pixel),
str(end_pixel),
595 str(start_line),
str(end_line),
597 logging.debug(
'Executing l1aextract_modis command: "%s"',
598 " ".join(
str(x)
for x
in l1aextract_cmd))
604 Sets up and runs the MODIS GEO script.
608 args = [proc.input_file]
609 args.append(
'--output={}'.format(proc.output_file))
614 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
619 Sets up and runs the MODIS L1A script.
622 args = [proc.input_file]
623 args.append(
'--output={}'.format(proc.output_file))
628 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
636 args = [
'-o', proc.output_file]
640 args.append(proc.input_file)
641 if not proc.geo_file
is None:
642 args.append(proc.geo_file)
645 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
650 Sensor SeaWiFS contains SeaWiFS sepcific recipe and processing method.
655 'level 1a': processing_rules.build_rule(
'level 1a', [
'level 0'],
657 'l1aextract': processing_rules.build_rule(
'l1aextract',
661 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'l1'],
665 'level 1b': processing_rules.build_rule(
'level 1b', [
'level 1a'],
667 'l2gen': processing_rules.build_rule(
'l2gen', [
'l1'], self.
run_l2gen,
669 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
671 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
675 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
677 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
679 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
689 'level 1b',
'l2gen',
'l2extract',
690 'l2brsgen',
'l2bin',
'l3bin',
698 Set up and run l1aextract_seawifs.
700 if 'SWlon' in proc.par_data
and 'SWlat' in proc.par_data
and\
701 'NElon' in proc.par_data
and 'NElat' in proc.par_data:
703 if (start_line
is None)
or (end_line
is None)
or (start_pixel
is None)\
704 or (end_pixel
is None):
705 err_msg =
'Error! Cannot compute l1aextract_seawifs coordinates.'
707 l1aextract_prog = os.path.join(proc.ocssw_bin,
'l1aextract_seawifs')
708 l1aextract_cmd = [l1aextract_prog, proc.input_file,
709 str(start_pixel),
str(end_pixel),
710 str(start_line),
str(end_line),
'1',
'1',
712 logging.debug(
'Executing l1aextract_seawifs command: "%s"',
713 " ".join(
str(x)
for x
in l1aextract_cmd))
719 Sensor VIIRS contains VIIRS sepcific recipe and processing method..
724 'level 1a': processing_rules.build_rule(
'level 1a', [
'nothing lower'],
726 'l1brsgen': processing_rules.build_rule(
'l1brsgen', [
'l1',
'geo'],
730 'geo': processing_rules.build_rule(
'geo', [
'level 1a'],
732 'l1aextract': processing_rules.build_rule(
'l1aextract',
736 'level 1b': processing_rules.build_rule(
'level 1b', [
'level 1a',
'geo'],
738 'l2gen': processing_rules.build_rule(
'l2gen', [
'l1',
'geo'],
740 'l2extract': processing_rules.build_rule(
'l2extract', [
'l2gen'],
742 'l2brsgen': processing_rules.build_rule(
'l2brsgen', [
'l2gen'],
746 'l2bin': processing_rules.build_rule(
'l2bin', [
'l2gen'], self.
run_l2bin,
748 'l3bin': processing_rules.build_rule(
'l3bin', [
'l2bin'], self.
run_l3bin,
750 'l3mapgen': processing_rules.build_rule(
'l3mapgen', [
'l2bin'],
758 self.
rules_order = [
'level 1a',
'geo',
'l1aextract',
'level 1b',
'l1brsgen',
759 'l2gen',
'l2extract',
'l2bin',
760 'l2brsgen',
'l3bin',
'l3mapgen']
767 Set up and run the geolocate_viirs program, returning the exit status of the run.
769 logging.debug(
'In run_geolocate_viirs')
775 err_msg =
'Error! Cannot find program geolocate_viirs.'
776 logging.info(err_msg)
778 args = [
'-ifile={}'.format(proc.input_file),
'-geofile_mod={}'.format(proc.output_file)]
783 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
787 logging.debug(
'In run_viirs_l1b')
791 args = [
'ifile={}'.format(proc.input_file),
'l1bfile_mod={}'.format(proc.output_file)]
802 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
807 Set up and run l1aextract_viirs.
809 if 'SWlon' in proc.par_data
and 'SWlat' in proc.par_data
and\
810 'NElon' in proc.par_data
and 'NElat' in proc.par_data:
812 elif 'sline' in proc.par_data
and 'eline' in proc.par_data
and\
813 'spixl' in proc.par_data
and 'epixl' in proc.par_data:
814 start_line = proc.par_data[
'sline']
815 end_line = proc.par_data[
'eline']
816 start_pixel = proc.par_data[
'spixl']
817 end_pixel = proc.par_data[
'epixl']
819 if (start_line
is None)
or (end_line
is None)
or (start_pixel
is None)\
820 or (end_pixel
is None):
821 err_msg =
'Error! Cannot find l1aextract_viirs coordinates.'
823 l1aextract_prog = os.path.join(proc.ocssw_bin,
'l1aextract_viirs')
824 l1aextract_cmd = [l1aextract_prog, proc.input_file,
825 str(start_pixel),
str(end_pixel),
826 str(start_line),
str(end_line),
828 logging.debug(
'Executing l1aextract_viirs command: "%s"',
829 " ".join(
str(x)
for x
in l1aextract_cmd))
835 Returns an obpg_data_file object for the file named in file_specification.
838 (ftype, sensor) = ftyper.get_file_type()
839 (stime, etime) = ftyper.get_file_times()
840 obpg_data_file_obj = obpg_data_file.ObpgDataFile(file_specification, ftype,
841 sensor, stime, etime,
843 return obpg_data_file_obj
847 Returns the directory in which the program named in prog_name is found.
848 None is returned if the program is not found.
851 candidate_subdirs = [
'bin',
'scripts']
852 for subdir
in candidate_subdirs:
853 cand_path = os.path.join(OCSSWROOT_DIR, subdir, prog_name)
854 if os.path.exists(cand_path):
861 Create a file listing the names of the files to be processed.
863 with open(filename,
'wt')
as file_list_file:
864 for fname
in file_list:
865 file_list_file.write(fname +
'\n')
869 Build the parameter file for L2 processing.
871 dt_stamp = datetime.datetime.today()
872 par_name =
''.join([
'L2_', dt_stamp.strftime(
'%Y%m%d%H%M%S'),
'.par'])
873 par_path = os.path.join(cfg_data.hidden_dir, par_name)
874 with open(par_path,
'wt')
as par_file:
875 par_file.write(
'# Automatically generated par file for l2gen\n')
876 par_file.write(
'ifile=' + input_file +
'\n')
877 if not geo_file
is None:
878 par_file.write(
'geofile=' + geo_file +
'\n')
879 par_file.write(
'ofile=' + output_file +
'\n')
880 for l2_opt
in par_contents:
881 if l2_opt !=
'ifile' and l2_opt !=
'geofile' \
882 and l2_opt !=
'ofile' and l2_opt !=
'odir' \
883 and not l2_opt
in FILE_USE_OPTS:
884 par_file.write(l2_opt +
'=' + par_contents[l2_opt] +
'\n')
889 Check command line options
897 if not os.path.exists(options.ifile):
898 err_msg =
'Error! The specified input file, {0}, does not exist.'. \
899 format(options.ifile)
904 Delete unwanted files created during processing.
907 print (
"Cleaning up files")
913 for filepath
in delete_list:
915 print (
'Deleting {0}'.format(filepath))
920 hidden_files = os.listdir(cfg_data.hidden_dir)
921 par_files = [f
for f
in hidden_files
if f.endswith(
'.par')]
922 for par_file
in par_files:
923 par_path = os.path.join(cfg_data.hidden_dir, par_file)
924 file_age = round(time.time()) - os.path.getmtime(par_path)
925 if file_age > cfg_data.max_file_age:
927 print (
'Deleting {0}'.format(par_path))
932 if not files_deleted:
933 print (
'No files were found for deletion.')
935 elif files_deleted == 1:
936 print (
'One file was deleted.')
939 print (
'A total of {0} files were deleted.'.format(files_deleted))
944 Returns a list containing all the levels from all the rules sets.
946 set_key =
list(rules_sets.keys())[0]
947 logging.debug(
'set_key = %s', (set_key))
948 lvls_lst = [(lvl, [set_key])
for lvl
in rules_sets[set_key].rules_order[1:]]
949 for rules_set_name
in list(rules_sets.keys())[1:]:
950 for lvl_name
in rules_sets[rules_set_name].rules_order[1:]:
951 names_list = [lst_item[0]
for lst_item
in lvls_lst]
952 if lvl_name
in names_list:
953 lvls_lst[names_list.index(lvl_name)][1].append(rules_set_name)
955 prev_ndx = rules_sets[rules_set_name].rules_order.index(lvl_name) - 1
956 if rules_sets[rules_set_name].rules_order[prev_ndx]
in names_list:
957 ins_ndx = names_list.index(rules_sets[rules_set_name].rules_order[prev_ndx]) + 1
960 lvls_lst.insert(ins_ndx, (lvl_name, [rules_set_name]))
966 Creates the message to be displayed when help is provided.
970 %prog [options] parameter_file
972 The parameter_file is similar to, but not exactly like, parameter
973 files for OCSSW processing programs:
974 - It has sections separated by headers which are denoted by "["
976 The section named "main" is required. Its allowed options are:
977 ifile - Required entry naming the input file(s) to be processed.
978 use_ancillary - use near real time ancillary data
979 deletefiles - delete all the intermediate data files genereated
980 overwrite - overwrite any data files which already exist
981 use_existing - use any data files which already exist
983 Simultaneous use of both the overwrite and use_existing options
986 The names for other sections are the programs for which that section's
987 entries are to be applied. Intermediate sections which are required for the
988 final level of processing do not need to be defined if their default options
989 are acceptable. A section can be empty. The final level of processing
990 must have a section header, even if no entries appear within that section.
991 - Entries within a section appear as key=value. Comma separated lists of
992 values can be used when appropriate.
993 - Comments are marked by "#"; anything appearing on a line after that
994 character is ignored. A line beginning with a "#" is completely ignored.
996 In addition to the main section, the following sections are allowed:
997 Section name: Applicable Instrument(s):
998 ------------- -------------------------\n"""
1001 for lname
in level_names:
1002 lvl_name_help +=
' {0:24s}{1}\n'.\
1003 format(lname[0] +
':',
', '.join(lname[1]))
1005 message += lvl_name_help
1009 # Sample par file for %prog.
1011 ifile=2010345034027.L1A_LAC
1014 # final processing level
1020 Perform the processing for each step (element of processor_list) needed.
1022 global input_file_data
1024 files_to_delete = []
1025 input_files_list = []
1029 skip_par_ifile =
True
1030 if os.path.exists(cmd_line_ifile):
1031 input_files_list = [cmd_line_ifile]
1033 msg =
'Error! Specified ifile {0} does not exist.'.\
1034 format(cmd_line_ifile)
1037 skip_par_ifile =
False
1038 if par_contnts[
'main']:
1039 if (
not skip_par_ifile)
and (
not 'ifile' in par_contnts[
'main']):
1040 msg =
'Error! No ifile specified in the main section of {0}.'.\
1047 cfg_data.deletefiles =
True
1049 cfg_data.use_existing =
True
1051 cfg_data.overwrite =
True
1052 if 'use_ancillary' in par_contnts[
'main']
and \
1053 int(par_contnts[
'main'][
'use_ancillary']) == 0:
1054 cfg_data.get_anc =
False
1055 if 'odir' in par_contnts[
'main']:
1056 dname = par_contnts[
'main'][
'odir']
1057 if os.path.exists(dname):
1058 if os.path.isdir(dname):
1059 if cfg_data.output_dir_is_settable:
1060 cfg_data.output_dir = os.path.realpath(dname)
1062 log_msg =
'Ignoring par file specification for output directory, {0}; using command line value, {1}.'.format(par_contnts[
'main'][
'odir'], cfg_data.output_dir)
1063 logging.info(log_msg)
1065 msg =
'Error! {0} is not a directory.'.format(dname)
1068 msg =
'Error! {0} does not exist.'.format(dname)
1071 logging.debug(
'cfg_data.overwrite: ' +
str(cfg_data.overwrite))
1072 logging.debug(
'cfg_data.use_existing: ' +
str(cfg_data.use_existing))
1073 logging.debug(
'cfg_data.deletefiles: ' +
str(cfg_data.deletefiles))
1074 if cfg_data.overwrite
and cfg_data.use_existing:
1075 err_msg =
'Error! Incompatible options overwrite and use_existing were found in {0}.'.format(par_file)
1077 if len(input_files_list) == 1:
1078 if MetaUtils.is_ascii_file(input_files_list[0])
and not MetaUtils.is_metadata_file(input_files_list[0]):
1081 if not input_file_data:
1082 log_and_exit(
'No valid data files were specified for processing.')
1083 logging.debug(
"input_file_data: " +
str(input_file_data))
1087 get_processors(src_files, input_file_data, par_contnts, files_to_delete)
1093 err_msg =
"Unrecoverable error encountered in processing."
1097 if cfg_data.verbose:
1098 print (
"Processing complete.")
1100 logging.debug(
"Processing complete.")
1105 Execute what is contained in command and then output the results to log
1106 files and the console, as appropriate.
1109 print (
"Entering execute_command, cfg_data.verbose =",
1111 log_msg =
'Executing command:\n {0}'.format(command)
1112 logging.debug(log_msg)
1115 subproc = subprocess.run(command, capture_output=
True, text=
True, shell=
False)
1116 std_out, err_out = subproc.stdout, subproc.stderr
1117 status = subproc.returncode
1118 logging.info(std_out)
1119 logging.info(err_out)
1120 if cfg_data.verbose:
1126 Returns a single section (e.g. L1a, GEO, L1B, L2, etc.) from the "par" file.
1129 for key
in list(par_contents[section].keys()):
1130 sect_dict[key] = par_contents[section][key]
1135 Searches for a GEO file corresponding to inp_file. If that GEO file exists,
1136 returns that file name; otherwise, returns None.
1138 src_dir = os.path.dirname(inp_file)
1139 src_base = os.path.basename(inp_file)
1140 src_base_tmp = src_base.replace(
"L1B",
"GEO")
1141 geo_base = src_base_tmp.replace(
"_LAC",
"")
1143 geo_file = os.path.join(src_dir, geo_base)
1144 if not os.path.exists(geo_file):
1150 Searches for a GEO file corresponding to inp_file. If that GEO file exists,
1151 returns that file name; otherwise, returns None.
1153 src_dir = os.path.dirname(inp_file)
1154 src_base = os.path.basename(inp_file)
1155 if instrument.find(
'hawkeye') != -1:
1156 src_base_tmp = src_base.replace(
"L1A",
"GEO")
1157 geo_base = src_base_tmp.replace(
"nc",
"hdf")
1158 elif instrument.find(
'modis') != -1:
1159 if lvl.find(
'level 1a') != -1:
1160 src_base_tmp = src_base.replace(
"L1A",
"GEO")
1161 geo_base_tmp = src_base_tmp.replace(
"_LAC",
"")
1162 if geo_base_tmp.find(
'MODIS') != -1:
1163 geo_base = geo_base_tmp.replace(
"nc",
"hdf")
1165 geo_base = geo_base_tmp
1166 elif lvl.find(
'level 1b') != -1:
1167 src_base_tmp = src_base.replace(
"L1B",
"GEO")
1168 geo_base = src_base_tmp.replace(
"_LAC",
"")
1169 elif instrument.find(
'viirs') != -1:
1170 if lvl.find(
'level 1a') != -1:
1171 geo_base_tmp = src_base.replace(
"L1A",
"GEO-M")
1172 elif lvl.find(
'level 1b') != -1:
1173 geo_base_tmp = src_base.replace(
"L1B",
"GEO")
1174 if geo_base_tmp.find(
'VIIRS') != -1:
1175 geo_base_tmp2 = geo_base_tmp.replace(
"nc",
"hdf")
1176 geo_base = geo_base_tmp2.replace(
"GEO-M",
"GEO_M")
1178 geo_base = geo_base_tmp
1180 geo_file = os.path.join(src_dir, geo_base)
1181 if not os.path.exists(geo_file):
1187 Searches for a GEO file corresponding to first_svm_file. If that GEO file
1188 exists, returns that file name; otherwise, returns None.
1190 fname = first_svm_file.replace(
'SVM01',
'GMTCO').rstrip()
1191 if not os.path.exists(fname):
1197 Returns the output file for a "batch" run, i.e. a process that can accept
1198 multiple inputs, such as l2bin or l3bin.
1200 mission_prefixes = [
'A',
'C',
'O',
'S',
'T']
1202 if not len(file_set):
1203 err_msg =
"Error! An output file name could not be determined."
1205 elif len(file_set) == 1:
1206 stem = os.path.splitext(file_set[0])[0]
1208 earliest_file = file_set[0]
1209 latest_file = file_set[0]
1212 for cur_file
in file_set[1:]:
1214 if file_date < earliest_file_date:
1215 earliest_file = cur_file
1216 earliest_file_date = file_date
1217 elif file_date > latest_file_date:
1218 latest_file = cur_file
1219 latest_file_date = file_date
1220 if (earliest_file[0] == latest_file[0])
and \
1221 (earliest_file[0]
in mission_prefixes):
1222 stem = earliest_file[0]
1225 earliest_file_date_stamp = earliest_file_date.strftime(
'%Y%j')
1226 latest_file_date_stamp = latest_file_date.strftime(
'%Y%j')
1227 if earliest_file_date_stamp == latest_file_date_stamp:
1228 stem += earliest_file_date_stamp
1230 stem += earliest_file_date_stamp + latest_file_date_stamp
1231 return ''.join([stem,
'.', suffix])
1235 If found in par_contents, the value for the option specified by opt_text
1236 is returned; otherwise, False is returned.
1239 if opt_text
in par_contents[
'main']:
1240 opt_str = par_contents[
'main'][opt_text].upper()
1241 opt_found = mlp_utils.is_option_value_true(opt_str)
1246 Run the lonlat2pixline program and return the parameters found.
1250 in_file = proc.geo_file
1253 in_file = proc.input_file
1255 proc.par_data[
'SWlon'],
1256 proc.par_data[
'SWlat'],
1257 proc.par_data[
'NElon'],
1258 proc.par_data[
'NElat']]
1259 lonlat_prog = os.path.join(proc.ocssw_bin,
'lonlat2pixline')
1260 lonlat_cmd = [lonlat_prog]
1261 lonlat_cmd.extend(args)
1262 logging.debug(
'Executing lonlat2pixline command: "%s"',
" ".join(
str(x)
for x
in lonlat_cmd))
1263 process_output = subprocess.run(lonlat_cmd, capture_output=
True, text=
True, shell=
False)
1264 lonlat_output = process_output.stdout.splitlines()
1269 for line
in lonlat_output:
1270 line_text =
str(line).strip(
"'")
1271 if 'sline' in line_text:
1272 start_line =
int(line_text.split(
'=')[1])
1273 if 'eline' in line_text:
1274 end_line =
int(line_text.split(
'=')[1])
1275 if 'spixl' in line_text:
1276 start_pixel =
int(line_text.split(
'=')[1])
1277 if 'epixl' in line_text:
1278 end_pixel =
int(line_text.split(
'=')[1])
1279 return start_line, end_line, start_pixel, end_pixel
1283 Get a Python Date object from a recognized file name's year and day of year.
1285 base_filename = os.path.basename(filename)
1286 if re.match(
r'[ACMOQSTV]\d\d\d\d\d\d\d.*', base_filename):
1287 year =
int(base_filename[1:5])
1288 doy =
int(base_filename[5:8])
1289 elif re.match(
r'\d\d\d\d\d\d\d.*', base_filename):
1291 year =
int(base_filename[0:4])
1292 doy =
int(base_filename[4:7])
1293 elif re.match(
r'\w*_npp_d\d\d\d\d\d\d\d_.*', base_filename):
1295 prefix_removed_name = re.sub(
r'\w*_npp_d',
'', base_filename)
1296 year =
int(prefix_removed_name[0:4])
1297 doy =
int(prefix_removed_name[5:7])
1299 err_msg =
'Unable to determine date for {0}'.format(filename)
1301 file_date = datetime.datetime(year, 1, 1) + datetime.timedelta(doy - 1)
1306 Returns the values of the file handling options in par_contents.
1311 return deletefiles, use_existing, overwrite
1315 Get input files found in the uber par file's ifile line, a file list file,
1316 or both. Ensure that the list contains no duplicates.
1320 from_infilelist = []
1321 if 'ifile' in par_data[
'main']:
1322 inp_file_str = par_data[
'main'][
'ifile'].split(
'#', 2)[0]
1323 cleaned_str = re.sub(
r'[\t,:\[\]()"\']',
' ', inp_file_str)
1324 from_ifiles = cleaned_str.split()
1325 if 'infilelist' in par_data[
'main']:
1326 infilelist_name = par_data[
'main'][
'infilelist']
1327 if os.path.exists(infilelist_name):
1328 if os.path.isfile(infilelist_name)
and \
1329 os.access(infilelist_name, os.R_OK):
1330 with open(infilelist_name,
'rt')
as in_file_list_file:
1331 inp_lines = in_file_list_file.readlines()
1332 from_infilelist = [fn.rstrip()
for fn
in inp_lines
1333 if not re.match(
r'^\s*#', fn)]
1334 if len(from_ifiles) == 0
and len(from_infilelist) == 0:
1338 return list(
set(from_ifiles + from_infilelist))
1342 Returns a dictionary with the the file_type (L0, L1A, L2, etc) and
1343 instrument for each file in the input list.
1347 'level 0':
'level 0',
1348 'level 1 browse data':
'l1brsgen',
1349 'level 1a':
'level 1a',
1350 'level 1b':
'level 1b',
1351 'level 1c':
'level 1c',
1354 'level 3 binned':
'l3bin'
1357 input_file_type_data = {}
1358 for inp_file
in input_files_list:
1364 file_type, file_instr = file_typer.get_file_type()
1371 if file_type.lower()
in converter:
1372 file_type = converter[file_type.lower()]
1373 input_file_type_data[inp_file] = (file_type, file_instr.lower())
1377 warn_msg =
"Warning: Unable to determine a type for file {0}. It will not be processed.".format(inp_file)
1379 logging.info(warn_msg)
1380 return input_file_type_data
1384 Create processor objects for products which are needed, but not explicitly
1385 specified in the par file.
1387 existing_products = [proc.target_type
for proc
in existing_procs]
1389 lowest_source_level)
1390 intermediate_processors = []
1391 for prod
in intermediate_products:
1394 if not prod
in existing_products:
1395 new_proc = processor.Processor(sensor, rules, prod, {},
1396 cfg_data.hidden_dir)
1397 intermediate_processors.append(new_proc)
1398 return intermediate_processors
1401 lowest_source_level):
1403 Find products which are needed, but not explicitly specified by the
1407 for prog
in existing_prod_names:
1409 lowest_source_level)
1410 if not isinstance(candidate_progs,
type(
None)):
1411 for candidate_prog
in candidate_progs:
1412 required_progs.append(candidate_prog)
1414 required_progs.sort()
1415 return required_progs
1419 Returns the extension for an L2 file. For the time being, this is
1420 just '.L2'; however, different extensions may be wanted in the future, thus
1421 this function is in place.
1427 Returns the extension for an L3 Binned file. For the time being, this is
1428 just '.L3bin'; however, different extensions may be wanted in the future,
1429 thus this function is in place.
1435 Find the level of the lowest level source file to be processed.
1437 order = [
'level 1a',
'geo',
'level 1b',
'l2gen',
1438 'l2bin',
'l3bin',
'l3mapgen']
1439 if len(source_files) == 1:
1440 return list(source_files.keys())[0]
1442 lowest =
list(source_files.keys())[0]
1443 for key
in list(source_files.keys())[1:]:
1445 if order.index(key) < order.index(lowest):
1451 Extract the options for a program to be run from the corresponding data in
1455 for key
in par_data:
1456 if key !=
'ofile' and key !=
'odir' and not key.lower()
in FILE_USE_OPTS:
1458 options.append(
'{}={}'.format(key,par_data[key]))
1465 Determine what the output name would be if targ_prog is run on input_files.
1467 cl_opts = optparse.Values()
1468 cl_opts.suite = suite
1469 cl_opts.oformat = oformt
1470 cl_opts.resolution = res
1471 if not isinstance(inp_files, list):
1482 Determine the output name for a program to be run.
1486 if input_name
in input_files:
1487 if input_files[input_name][0] ==
'level 0' and \
1488 input_files[input_name][1].find(
'modis') != -1:
1489 if input_files[input_name][1].find(
'aqua') != -1:
1494 if os.path.exists(input_name +
'.const'):
1495 with open(input_name +
'.const')
as constructor_file:
1496 constructor_data = constructor_file.readlines()
1497 for line
in constructor_data:
1498 if line.find(
'starttime=') != -1:
1499 start_time = line[line.find(
'=') + 1].strip()
1501 time_stamp = ProcUtils.date_convert(start_time,
't',
'j')
1503 if re.match(
r'MOD00.P\d\d\d\d\d\d\d\.\d\d\d\d', input_name):
1504 time_stamp = input_name[7:14] + input_name[15:19] +
'00'
1506 err_msg =
"Cannot determine time stamp for input file {0}".\
1509 output_name = first_char + time_stamp +
'.L1A'
1512 (dirname, basename) = os.path.split(input_name)
1513 basename_parts = basename.rsplit(
'.', 2)
1514 output_name = os.path.join(dirname, basename_parts[0] +
'.' +
1517 (dirname, basename) = os.path.split(input_name)
1518 basename_parts = basename.rsplit(
'.', 2)
1519 output_name = os.path.join(dirname, basename_parts[0] +
'.' + suffix)
1524 Return the contents of the input "par" file.
1526 acceptable_par_keys = {
1527 'level 0' :
'level 0',
'l0' :
'level 0',
1528 'level 1a' :
'level 1a',
'l1a' :
'level 1a',
'l1agen':
'level 1a',
1529 'modis_L1A':
'level 1a',
1530 'l1brsgen':
'l1brsgen',
1532 'l1aextract':
'l1aextract',
1533 'l1aextract_modis':
'l1aextract_modis',
1534 'l1aextract_seawifs' :
'l1aextract_seawifs',
1535 'l1aextract_viirs' :
'l1aextract_viirs',
1536 'l1brsgen' :
'l1brsgen',
1537 'geo' :
'geo',
'modis_GEO':
'geo',
'geolocate_viirs':
'geo',
1538 'geolocate_hawkeye':
'geo',
1539 'level 1b' :
'level 1b',
'l1b' :
'level 1b',
'l1bgen' :
'level 1b',
1540 'modis_L1B':
'level 1b',
'calibrate_viirs':
'level 1b',
1541 'level 2' :
'l2gen',
1544 'l2brsgen' :
'l2brsgen',
1545 'l2extract' :
'l2extract',
1548 'l3mapgen' :
'l3mapgen',
1552 if cfg_data.verbose:
1553 print (
"Processing %s" % par_file)
1554 par_reader = uber_par_file_reader.ParReader(par_file,
1555 acceptable_single_keys,
1556 acceptable_par_keys)
1557 par_contents = par_reader.read_par_file()
1558 ori_keys =
list(par_contents.keys())
1559 for key
in ori_keys:
1560 if key
in acceptable_par_keys:
1561 if key != acceptable_par_keys[key]:
1562 par_contents[acceptable_par_keys[key]] = par_contents[key]
1563 del par_contents[key]
1565 acc_key_str =
', '.join(
list(acceptable_par_keys.keys()))
1566 err_msg =
"""Error! Parameter file {0} contains a section titled "{1}", which is not a recognized program.
1567 The recognized programs are: {2}""".format(par_file, key, acc_key_str)
1570 if 'main' in par_contents:
1573 err_msg =
'Error! Could not find section "main" in {0}'.format(par_file)
1575 return par_contents, input_files_list
1579 Determine the processors which are needed.
1582 for key
in list(par_contents.keys()):
1585 proc = processor.Processor(sensor, rules, key, section_contents,
1586 cfg_data.hidden_dir)
1587 processors.append(proc)
1591 lowest_source_level)
1597 Execute the processor.
1599 if proc.out_directory == cfg_data.hidden_dir:
1600 proc.out_directory = cfg_data.output_dir
1601 if proc.requires_batch_processing():
1602 logging.debug(
'Performing batch processing for ' +
str(proc))
1605 return out_file,
False
1607 if proc.rule_set.rules[proc.target_type].action:
1608 logging.debug(
'Performing nonbatch processing for ' +
str(proc))
1617 if success_count == 0:
1618 print(
'The {0} processor produced no output files.'.format(proc.target_type), flush=
True)
1619 msg =
'The {0} processor produced no output files.'.format(proc.target_type)
1622 return out_file, used_exsiting
1624 msg =
'-I- There is no way to create {0} files for {1}.'.format(proc.target_type, proc.instrument)
1629 Determine how to chain the processors together.
1631 order = [
'level 0',
'level 1a',
'level 1c',
'geo',
'l1aextract',
1632 'level 1b',
'l1brsgen',
'l2gen',
'l2extract',
'l2brsgen',
1633 'l2bin',
'l3bin',
'l3mapgen']
1634 key_list =
list(par_contents.keys())
1635 last_key = key_list[-1]
1636 if 'l2extract' in key_list:
1637 if not (
'l2gen' in key_list):
1638 pos = key_list.index(
'l2extract')
1639 key_list.insert(pos,
'l2gen')
1640 items =
list(par_contents.items())
1641 items.insert(pos, (
'l2gen', {}))
1642 par_contents = dict(items)
1643 elif 'l2brsgen' in key_list:
1644 if not (
'l2gen' in key_list):
1645 pos = key_list.index(
'l2brsgen')
1646 key_list.insert(pos,
'l2gen')
1647 items =
list(par_contents.items())
1648 items.insert(pos, (
'l2gen', {}))
1649 par_contents = dict(items)
1650 elif 'l2bin' in key_list:
1652 if not (
'l2gen' in key_list):
1653 pos = key_list.index(
'l2bin')
1654 key_list.insert(pos,
'l2gen')
1655 items =
list(par_contents.items())
1656 items.insert(pos, (
'l2gen', {}))
1657 par_contents = dict(items)
1658 elif 'l3bin' in key_list:
1660 if not (
'l3bin' in key_list):
1661 pos = key_list.index(
'l3bin')
1662 key_list.insert(pos,
'l2bin')
1663 items =
list(par_contents.items())
1664 items.insert(pos, (
'l2bin', {}))
1665 par_contents = dict(items)
1666 elif 'l3mapgen' in key_list:
1668 if not (
'l2gen' in key_list):
1669 pos = key_list.index(
'l3mapgen')
1670 key_list.insert(pos,
'l2gen')
1671 items =
list(par_contents.items())
1672 items.insert(pos, (
'l2gen', {}))
1673 par_contents = dict(items)
1674 for key
in key_list:
1677 if not order.index(key) > order.index(
'l2gen'):
1678 src_lvls =
list(src_files.keys())
1679 if not key
in src_files:
1681 for src_lvl
in src_lvls:
1682 if order.index(src_lvl) < order.index(
'l2gen'):
1683 for file
in src_files[src_lvl]:
1685 instrument = file_typer.get_file_type()[1].lower().split()[0]
1687 logging.debug(
"instrument: " + instrument)
1688 if instrument
in sensors_sets:
1689 rules = sensors_sets[instrument].recipe
1690 sensor = sensors_sets[instrument]
1692 rules = sensors_sets[
'general'].recipe
1693 sensor = sensors_sets[
'general']
1694 proc = processor.Processor(sensor, rules, key, section_contents,
1695 cfg_data.hidden_dir)
1696 proc.input_file = file
1697 if file_typer.get_file_type()[0].lower().find(
'level 0') == -1:
1698 if sensor.require_geo
and key !=
'geo':
1699 if 'geo' in src_lvls:
1700 proc.geo_file = src_files[
'geo'][0]
1702 proc.geo_file =
find_geo_file2(proc.input_file, instrument, src_lvl)
1704 if not proc.geo_file:
1705 if src_lvl.find(
'level 1b') != -1:
1706 err_msg =
'Error! Cannot produce GEO file for {0}, Need level 1a file'.format(file)
1708 logging.debug(err_msg , flush=
True)
1710 print (
'Skipping processing on file {0}.'.format(file), flush=
True)
1712 log_msg =
'Skipping processing on file {0}.'.format(file)
1713 logging.debug(log_msg)
1716 proc_geo = processor.Processor(sensor, rules,
'geo', {},
1717 cfg_data.hidden_dir)
1718 proc_geo.input_file = file
1719 print (
'Running geo on file {0}.'.format(file), flush=
True)
1721 log_msg =
'Processing for geo:'
1722 logging.debug(log_msg)
1723 proc.geo_file, used_existing =
exe_processor(proc_geo, src_files, src_lvl)
1724 if not proc.geo_file:
1725 print (
'Skipping processing on file {0}.'.format(file), flush=
True)
1727 log_msg =
'Skipping processing on file {0}.'.format(file)
1728 logging.debug(log_msg)
1730 if cfg_data.deletefiles
and not used_existing:
1732 files_to_delete.append(proc.geo_file)
1734 print (
'Used existing geo file {0}.'.format(proc.geo_file))
1736 log_msg =
'Used existing geo file {0}.'.format(proc.geo_file)
1737 logging.debug(log_msg)
1738 if key ==
'l2gen' and sensor.require_l1b_for_l2gen
and src_lvl.find(
'level 1b') == -1:
1739 proc_l1b = processor.Processor(sensor, rules,
'level 1b', {},
1740 cfg_data.hidden_dir)
1741 if sensor.require_geo:
1742 proc_l1b.input_file = file
1743 proc_l1b.geo_file = proc.geo_file
1744 print (
'Running level 1b on file {0}.'.format(file), flush=
True)
1746 log_msg =
'Processing for level 1b:'
1747 logging.debug(log_msg)
1748 proc.input_file, used_existing =
exe_processor(proc_l1b, src_files, src_lvl)
1749 if not proc.input_file:
1750 print (
'Skipping processing on file {0}.'.format(file), flush=
True)
1752 log_msg =
'Skipping processing on file {0}.'.format(file)
1753 logging.debug(log_msg)
1755 if cfg_data.deletefiles
and not used_existing:
1757 files_to_delete.append(proc.input_file)
1759 print (
'Used existing level 1b file {0}.'.format(proc.input_file))
1761 log_msg =
'Used existing level 1b file {0}.'.format(proc.input_file)
1762 logging.debug(log_msg)
1764 file_input = proc.input_file
1765 print (
'Running {0} on file {1}.'.format(proc.target_type, proc.input_file), flush=
True)
1767 log_msg =
'Processing for {0}:'.format(proc.target_type)
1768 logging.debug(log_msg)
1769 out_file, used_existing =
exe_processor(proc, src_files, src_lvl)
1771 src_files[key].append(out_file)
1773 print (
'Skipping processing on file {0}.'.format(file_input, flush=
True))
1775 log_msg =
'Skipping processing on file {0}.'.format(file_input)
1776 logging.debug(log_msg)
1778 if cfg_data.deletefiles
and not used_existing
and key != last_key:
1779 if out_file
and key.find(
'brsgen') == -1:
1780 files_to_delete.append(out_file)
1782 print (
'Used existing file {0}.'.format(out_file))
1784 log_msg =
'Used existing file {0}.'.format(out_file)
1785 logging.debug(log_msg)
1786 if key.find(
'l1aextract') != -1:
1787 src_files[
'level 1a'] = src_files[key]
1788 del src_files[
'l1aextract']
1789 if 'geo' in src_files:
1790 del src_files[
'geo']
1791 src_lvls.remove(
'geo')
1794 if key !=
'level 1a':
1795 proc_l1a = processor.Processor(sensor, rules,
'level 1a', {},
1796 cfg_data.hidden_dir)
1797 proc_l1a.input_file = file
1798 print (
'Running level 1a on file {0}.'.format(file), flush=
True)
1800 log_msg =
'Processing for level 1a:'
1801 logging.debug(log_msg)
1802 proc.input_file, used_existing =
exe_processor(proc_l1a, src_files, src_lvl)
1803 if not proc.input_file:
1804 print (
'Skipping processing on file {0}.'.format(file), flush=
True)
1806 log_msg =
'Skipping processing on file {0}.'.format(file)
1807 logging.debug(log_msg)
1809 if cfg_data.deletefiles
and not used_existing:
1811 files_to_delete.append(proc.input_file)
1813 print (
'Used existing level 1a file {0}.'.format(proc.input_file))
1815 log_msg =
'Used existing level 1a file {0}.'.format(proc.input_file)
1816 logging.debug(log_msg)
1817 if proc.input_file
and sensor.require_geo
and key !=
'geo' and key !=
'level 1a':
1818 proc.geo_file =
find_geo_file2(proc.input_file, instrument,
'level 1a')
1819 if not proc.geo_file:
1820 proc_geo = processor.Processor(sensor, rules,
'geo', {},
1821 cfg_data.hidden_dir)
1822 proc_geo.input_file = proc.input_file
1823 print (
'Running geo on file {0}.'.format(proc.input_file), flush=
True)
1825 log_msg =
'Processing for geo:'
1826 logging.debug(log_msg)
1827 proc.geo_file, used_existing =
exe_processor(proc_geo, src_files, src_lvl)
1828 if not proc.geo_file:
1829 print (
'Skipping processing on file {0}.'.format(proc.input_file), flush=
True)
1831 log_msg =
'Skipping processing on file {0}.'.format(proc.input_file)
1832 logging.debug(log_msg)
1834 if cfg_data.deletefiles
and not used_existing:
1836 files_to_delete.append(proc.geo_file)
1838 print (
'Used existing geo file {0}.'.format(proc.geo_file))
1840 log_msg =
'Used existing geo file {0}.'.format(proc.geo_file)
1841 logging.debug(log_msg)
1842 if key ==
'l2gen' and sensor.require_l1b_for_l2gen:
1843 proc_l1b = processor.Processor(sensor, rules,
'level 1b', {},
1844 cfg_data.hidden_dir)
1845 if sensor.require_geo:
1846 proc_l1b.input_file = proc.input_file
1847 proc_l1b.geo_file = proc.geo_file
1848 print (
'Running level 1b on file {0}.'.format(proc.input_file), flush=
True)
1850 log_msg =
'Processing for level 1b:'
1851 logging.debug(log_msg)
1852 file_input = proc.input_file
1853 proc.input_file, used_existing =
exe_processor(proc_l1b, src_files, src_lvl)
1854 if not proc.input_file:
1855 print (
'Skipping processing on file {0}.'.format(file_input), flush=
True)
1857 log_msg =
'Skipping processing on file {0}.'.format(file_input)
1858 logging.debug(log_msg)
1860 if cfg_data.deletefiles
and not used_existing:
1862 files_to_delete.append(proc.input_file)
1864 print (
'Used existing level 1b file {0}.'.format(proc_l1b.input_file))
1866 log_msg =
'Used existing level 1b file {0}.'.format(proc_l1b.input_file)
1867 logging.debug(log_msg)
1869 file_input = proc.input_file
1870 print (
'Running {0} on file {1}.'.format(proc.target_type, proc.input_file), flush=
True)
1872 log_msg =
'Processing for {0}:'.format(proc.target_type)
1873 logging.debug(log_msg)
1874 out_file, used_existing =
exe_processor(proc, src_files, src_lvl)
1876 src_files[key].append(out_file)
1878 print (
'Skipping processing on file {0}.'.format(file_input), flush=
True)
1880 log_msg =
'Skipping processing on file {0}.'.format(file_input)
1881 logging.debug(log_msg)
1883 if cfg_data.deletefiles
and not used_existing
and key != last_key:
1884 if out_file
and key.find(
'brsgen') == -1:
1885 files_to_delete.append(out_file)
1887 print (
'Used existing file {0}.'.format(out_file))
1889 log_msg =
'Used existing file {0}.'.format(out_file)
1890 logging.debug(log_msg)
1891 if key.find(
'l1aextract') != -1:
1892 src_files[
'level 1a'] = src_files[key]
1893 del src_files[
'l1aextract']
1894 if 'geo' in src_files:
1895 del src_files[
'geo']
1896 src_lvls.remove(
'geo')
1898 if len(src_files) > 1
and key !=
'geo' :
1899 if key.find(
'brsgen') != -1:
1902 del src_files[src_lvl]
1903 if len(src_files) > 1:
1904 if 'geo' in src_lvls:
1905 del src_files[
'geo']
1906 src_lvls.remove(
'geo')
1908 src_lvls =
list(src_files.keys())
1909 rules = sensors_sets[
'general'].recipe
1910 sensor = sensors_sets[
'general']
1911 if not key
in src_files:
1913 for src_lvl
in src_lvls:
1914 if not order.index(src_lvl) < order.index(
'l2gen'):
1915 for file
in src_files[src_lvl]:
1916 proc = processor.Processor(sensor, rules, key, section_contents,
1917 cfg_data.hidden_dir)
1918 proc.input_file = file
1919 for program
in proc.required_types:
1920 if not program
in src_files:
1921 proc1 = processor.Processor(sensor, rules, program, {},
1922 cfg_data.hidden_dir)
1923 proc1.input_file = file
1925 for program2
in proc1.required_types:
1926 if program2.find(src_lvl) == -1:
1927 proc2 = processor.Processor(sensor, rules, program2, {},
1928 cfg_data.hidden_dir)
1929 proc2.input_file = file
1931 print (
'Running {0} on file {1}.'.format(proc2.target_type, proc2.input_file), flush=
True)
1933 log_msg =
'Processing for {0}:'.format(proc2.target_type)
1934 logging.debug(log_msg)
1935 proc1.input_file, used_existing =
exe_processor(proc2, src_files, src_lvl)
1936 if not proc1.input_file:
1937 print (
'Skipping processing on file {0}.'.format(file), flush=
True)
1939 log_msg =
'Skipping processing on file {0}.'.format(file)
1940 logging.debug(log_msg)
1942 if cfg_data.deletefiles
and not used_existing:
1943 if proc1.input_file:
1944 files_to_delete.append(proc1.input_file)
1946 print (
'Used existing file {0}.'.format(proc1.input_file))
1948 log_msg =
'Used existing file {0}.'.format(proc1.input_file)
1949 logging.debug(log_msg)
1950 if proc1.input_file:
1951 file_input = proc1.input_file
1952 print (
'Running {0} on file {1}.'.format(proc1.target_type, proc1.input_file), flush=
True)
1954 log_msg =
'Processing for {0}:'.format(proc1.target_type)
1955 logging.debug(log_msg)
1956 proc.input_file, used_existing =
exe_processor(proc1, src_files, src_lvl)
1957 if not proc.input_file:
1958 print (
'Skipping processing on file {0}.'.format(file_input), flush=
True)
1960 log_msg =
'Skipping processing on file {0}.'.format(file_input)
1961 logging.debug(log_msg)
1963 if cfg_data.deletefiles:
1964 if proc.input_file
and not used_existing:
1965 files_to_delete.append(proc.input_file)
1967 print (
'Used existing file {0}.'.format(proc.input_file))
1969 log_msg =
'Used existing file {0}.'.format(proc.input_file)
1970 logging.debug(log_msg)
1971 del src_files[src_lvl]
1973 file_input = proc.input_file
1974 print (
'Running {0} on file {1}.'.format(proc.target_type, proc.input_file), flush=
True)
1976 log_msg =
'Processing for {0}:'.format(proc.target_type)
1977 logging.debug(log_msg)
1978 out_file, used_existing =
exe_processor(proc, src_files, program)
1980 src_files[key].append(out_file)
1982 print (
'Skipping processing on file {0}.'.format(file_input), flush=
True)
1984 log_msg =
'Skipping processing on file {0}.'.format(file_input)
1985 logging.debug(log_msg)
1988 if cfg_data.deletefiles
and not used_existing
and key != last_key:
1989 if out_file
and key.find(
'brsgen') == -1:
1990 files_to_delete.append(out_file)
1992 print (
'Used existing file {0}.'.format(out_file))
1994 log_msg =
'Used existing file {0}.'.format(out_file)
1995 logging.debug(log_msg)
1996 if program
in src_files:
1997 if proc.target_type.find(
'brsgen') != -1:
1998 del src_files[proc.target_type]
2000 del src_files[program]
2001 if key.find(
'l2extract') != -1:
2002 src_files[
'l2gen'] = src_files[key]
2003 del src_files[
'l2extract']
2004 if proc.requires_batch_processing:
2010 Returns the programs required too produce the desired final output.
2012 programs_to_run = []
2013 cur_rule = ruleset.rules[target_program]
2014 src_types = cur_rule.src_file_types
2015 if src_types[0] == cur_rule.target_type:
2016 programs_to_run = [target_program]
2018 for src_type
in src_types:
2019 if src_type
in ruleset.rules:
2020 if ruleset.order.index(src_type) > \
2021 ruleset.order.index(lowest_source_level):
2022 programs_to_run.insert(0, src_type)
2023 if len(src_types) > 1:
2024 programs_to_run.insert(0, src_types[1])
2026 lowest_source_level)
2027 for prog
in programs_to_add:
2028 programs_to_run.insert(0, prog)
2029 return programs_to_run
2033 :param source_files: list of source files
2034 :param proc_src_types: list of source types for the processor
2035 :param proc_src_ndx: index into the proc_src_types list pointing to the
2036 source type to use to get the input files
2037 :return: list of GEO files that correspond to the files in source_files
2039 inp_files = source_files[proc_src_types[proc_src_ndx]]
2041 for inp_file
in inp_files:
2044 geo_files.append(geo_file)
2046 err_msg =
'Error! Cannot find GEO ' \
2047 'file {0}.'.format(geo_file)
2053 Returns the set of source files needed.
2055 if len(proc_src_types) == 1:
2057 src_file_sets = source_files[src_key]
2068 err_msg =
'Error! Unable to determine what source files are required for the specified output files.'
2071 if requires_all_sources:
2072 if len(proc_src_types) == 2:
2073 if proc_src_types[0]
in source_files \
2074 and proc_src_types[1]
in source_files:
2075 src_file_sets =
list(zip(source_files[proc_src_types[0]],
2076 source_files[proc_src_types[1]]))
2078 if proc_src_types[0]
in source_files:
2079 if proc_src_types[1] ==
'geo':
2081 src_file_sets =
list(zip(source_files[proc_src_types[0]],
2084 err_msg =
'Error! Cannot find all {0} and' \
2085 ' {1} source files.'.format(proc_src_types[0],
2088 elif proc_src_types[1]
in source_files:
2089 if proc_src_types[0] ==
'geo':
2091 src_file_sets =
list(zip(source_files[proc_src_types[1]],
2094 err_msg =
'Error! Cannot find all {0} and' \
2095 ' {1} source files.'.format(proc_src_types[0],
2099 err_msg =
'Error! Cannot find all source files.'
2102 err_msg =
'Error! Encountered too many source file types.'
2105 for proc_src_type
in proc_src_types:
2106 if proc_src_type
in source_files:
2107 src_file_sets = source_files[proc_src_type]
2108 return src_file_sets
2112 Returns a dictionary containing the programs to be run (as keys) and the
2113 a list of files on which that program should be run.
2116 for file_path
in input_files:
2117 ftype = input_files[file_path][0]
2118 if ftype
in source_files:
2119 source_files[ftype].append(file_path)
2121 source_files[ftype] = [file_path]
2126 Return the list of source product types needed to produce the final product.
2128 src_prod_names = [targt_prod]
2129 targt_pos = ruleset.order.index(targt_prod)
2131 for pos
in range(targt_pos, 1, -1):
2132 for prod_name
in src_prod_names:
2133 if ruleset.rules[ruleset.order[pos]].target_type == prod_name:
2134 for src_typ
in ruleset.rules[ruleset.order[pos]].src_file_types:
2135 new_prod_names.append(src_typ)
2136 src_prod_names += new_prod_names
2137 return src_prod_names
2141 Returns an error message built from traceback data.
2143 exc_parts = [
str(l)
for l
in sys.exc_info()]
2144 err_type_parts =
str(exc_parts[0]).strip().split(
'.')
2145 err_type = err_type_parts[-1].strip(
"'>")
2146 tb_data = traceback.format_exc()
2147 tb_line = tb_data.splitlines()[-3]
2148 line_num = tb_line.split(
',')[1]
2149 st_data = traceback.extract_stack()
2150 err_file = os.path.basename(st_data[-1][0])
2151 msg =
'Error! The {0} program encountered an unrecoverable {1}, {2}, at {3} of {4}!'.\
2152 format(cfg_data.prog_name,
2153 err_type, exc_parts[1], line_num.strip(), err_file)
2160 sensors = dict(general=
Sensor(),
2171 Record error_msg in the debug log, then exit with error_msg going to stderr
2172 and an exit code of 1; see:
2173 http://docs.python.org/library/sys.html#exit.
2175 logging.info(error_msg)
2180 main processing function.
2188 version=
' '.join([
'%prog', __version__]))
2192 print (
"\nError! No file specified for processing.\n")
2193 cl_parser.print_help()
2205 options.verbose, options.overwrite,
2206 options.use_existing,
2207 options.deletefiles, options.odir)
2208 if not os.access(cfg_data.hidden_dir, os.R_OK):
2209 log_and_exit(
"Error! The working directory is not readable!")
2210 if os.path.exists(args[0]):
2211 log_timestamp = datetime.datetime.today().strftime(
'%Y%m%d%H%M%S')
2234 err_msg =
'Unanticipated error encountered during processing!'
2237 err_msg =
'Error! Parameter file {0} does not exist.'.\
2245 Get arguments and options from the calling command line.
2246 To be consistent with other OBPG programs, an underscore ('_') is used for
2247 multiword options, instead of a dash ('-').
2249 cl_parser.add_option(
'--debug', action=
'store_true', dest=
'debug',
2250 default=
False, help=optparse.SUPPRESS_HELP)
2251 cl_parser.add_option(
'-d',
'--deletefiles', action=
'store_true',
2252 dest=
'deletefiles', default=
False,
2253 help=
'delete files created during processing')
2254 cl_parser.add_option(
'--ifile', action=
'store', type=
'string',
2255 dest=
'ifile', help=
"input file")
2256 cl_parser.add_option(
'--output_dir',
'--odir',
2257 action=
'store', type=
'string', dest=
'odir',
2258 help=
"user specified directory for output")
2259 cl_parser.add_option(
'--overwrite', action=
'store_true',
2260 dest=
'overwrite', default=
False,
2261 help=
'overwrite files which already exist (default = stop processing if file already exists)')
2267 cl_parser.add_option(
'--use_existing', action=
'store_true',
2268 dest=
'use_existing', default=
False,
2269 help=
'use files which already exist (default = stop processing if file already exists)')
2270 cl_parser.add_option(
'-v',
'--verbose',
2271 action=
'store_true', dest=
'verbose', default=
False,
2272 help=
'print status messages to stdout')
2274 (options, args) = cl_parser.parse_args()
2275 for ndx, cl_arg
in enumerate(args):
2276 if cl_arg.startswith(
'par='):
2277 args[ndx] = cl_arg.lstrip(
'par=')
2278 if options.overwrite
and options.use_existing:
2279 log_and_exit(
'Error! Options overwrite and use_existing cannot be ' + \
2280 'used simultaneously.')
2281 return options, args
2285 Reads flf_name and returns the list of files to be processed.
2289 with open(flf_name,
'rt')
as flf:
2290 inp_lines = flf.readlines()
2291 for line
in inp_lines:
2292 fname = line.split(
'#')[0].strip()
2294 if os.path.exists(fname):
2295 files_list.append(fname)
2297 bad_lines.append(fname)
2298 if len(bad_lines) > 0:
2299 err_msg =
'Error! File {0} specified the following input files which could not be located:\n {1}'.\
2300 format(flf_name,
', '.join([bl
for bl
in bad_lines]))
2306 Run a processor, e.g. l2bin, which processes batches of files.
2309 if os.path.exists((file_set[0]))
and tarfile.is_tarfile(file_set[0]):
2310 processor.input_file = file_set[0]
2312 timestamp = time.strftime(
'%Y%m%d_%H%M%S', time.gmtime(time.time()))
2313 file_list_name = cfg_data.hidden_dir + os.sep +
'files_' + \
2314 processor.target_type +
'_' + timestamp +
'.lis'
2315 with open(file_list_name,
'wt')
as file_list:
2316 for fname
in file_set:
2317 file_list.write(fname +
'\n')
2318 processor.input_file = file_list_name
2321 for fspec
in file_set:
2323 data_file_list.append(dfile)
2324 if 'suite' in processor.par_data:
2325 finder_opts[
'suite'] = processor.par_data[
'suite']
2326 elif 'prod' in processor.par_data:
2327 finder_opts[
'suite'] = processor.par_data[
'prod']
2328 if 'resolution' in processor.par_data:
2329 finder_opts[
'resolution'] = processor.par_data[
'resolution']
2330 if 'oformat' in processor.par_data:
2331 finder_opts[
'oformat'] = processor.par_data[
'oformat']
2335 if processor.output_file:
2336 processor.output_file = os.path.join(processor.out_directory,
2337 processor.output_file )
2339 processor.output_file = os.path.join(processor.out_directory,
2341 processor.target_type,
2344 log_msg =
"Running {0} with input file {1} to generate {2} ".\
2345 format(processor.target_type,
2346 processor.input_file,
2347 processor.output_file)
2348 logging.debug(log_msg)
2350 return processor.output_file
2354 Run a processor which deals with single input files (or pairs of files in
2355 the case of MODIS L1B processing in which GEO files are also needed).
2363 used_existing =
False
2366 cl_opts = optparse.Values()
2367 if 'suite' in processor.par_data:
2368 cl_opts.suite = processor.par_data[
'suite']
2369 elif 'prod' in processor.par_data:
2370 cl_opts.suite = processor.par_data[
'prod']
2372 cl_opts.suite =
None
2373 if 'resolution' in processor.par_data:
2374 cl_opts.resolution = processor.par_data[
'resolution']
2376 cl_opts.resolution =
None
2377 if 'oformat' in processor.par_data:
2378 cl_opts.oformat = processor.par_data[
'oformat']
2380 cl_opts.oformat =
None
2384 if processor.output_file:
2385 output_file = os.path.join(processor.out_directory, processor.output_file)
2387 output_file = os.path.join(processor.out_directory,
2390 print (
'in run_nonbatch_processor, output_file = ' + output_file)
2392 processor.output_file = output_file
2400 if (
not os.path.exists(output_file))
or cfg_data.overwrite:
2401 if cfg_data.verbose:
2403 print (
'\nRunning ' +
str(processor))
2405 proc_status = processor.execute()
2411 msg =
"Error! Status {0} was returned during {1} {2} processing.".\
2412 format(proc_status, processor.sensor.name,
2413 processor.target_type)
2419 elif not cfg_data.use_existing:
2420 log_and_exit(
'Error! Target file {0} already exists.'.\
2421 format(output_file))
2423 used_existing =
True
2424 processor.input_file =
''
2425 processor.output_file =
''
2426 return output_file, used_existing
2430 Build the command to run the processing script which is passed in.
2433 args = [
'ifile={}'.format(proc.input_file),
'ofile={}'.format(proc.output_file)]
2438 logging.debug(
'\nRunning: {}'.format(
" ".join(
str(x)
for x
in cmd)))
2445 Opens log file(s) for debugging.
2447 info_log_name =
''.join([
'Processor_', time_stamp,
'.log'])
2448 debug_log_name =
''.join([
'multilevel_processor_debug_', time_stamp,
2450 info_log_path = os.path.join(cfg_data.output_dir, info_log_name)
2451 debug_log_path = os.path.join(cfg_data.output_dir, debug_log_name)
2452 mlp_logger = logging.getLogger()
2455 info_hndl = logging.FileHandler(info_log_path)
2456 info_hndl.setLevel(logging.INFO)
2457 mlp_logger.addHandler(info_hndl)
2460 debug_hndl = logging.FileHandler(debug_log_path)
2461 debug_hndl.setLevel(logging.DEBUG)
2462 mlp_logger.addHandler(debug_hndl)
2463 logging.debug(
'Starting ' + os.path.basename(sys.argv[0]) +
' at ' +
2464 datetime.datetime.now().strftime(
"%Y-%m-%d %H:%M:%S"))
2468 Returns a list with no duplicates. Somewhat borrowed from:
2469 http://www.peterbe.com/plog/uniqifiers-benchmark (example f5)
2473 for item
in orig_list:
2474 if item
not in seen_items:
2475 seen_items[item] = 1
2476 uniqified_list.append(item)
2477 return uniqified_list
2485 FILE_USE_OPTS = [
'deletefiles',
'overwrite',
'use_existing']
2488 'l1brsgen':
'L1B_BRS',
2489 'l1aextract':
'L1A.sub',
2490 'l1aextract_viirs':
'L1A.sub',
2491 'l1aextract_seawifs':
'L1A.sub',
2492 'l1aextract_modis':
'L1A.sub',
2495 'l2brsgen':
'L2_BRS',
2496 'l2extract':
'L2.sub',
2502 'level 1b':
'L1B_LAC',
2505 input_file_data = {}
2508 if os.environ[
'OCSSWROOT']:
2509 OCSSWROOT_DIR = os.environ[
'OCSSWROOT']
2510 logging.debug(
'OCSSWROOT -> %s', OCSSWROOT_DIR)
2512 sys.exit(
'Error! Cannot find OCSSWROOT environment variable.')
2514 if __name__ ==
"__main__":