14 from datetime
import datetime, date, timedelta
16 from pathlib
import Path
18 IODA_CONV_PATH = Path(__file__).parent/
"@SCRIPT_LIB_PATH@"
19 if not IODA_CONV_PATH.is_dir():
20 IODA_CONV_PATH = Path(__file__).parent/
'..'/
'lib-python'
21 sys.path.append(
str(IODA_CONV_PATH.resolve()))
23 import ioda_conv_ncio
as iconv
24 from collections
import defaultdict, OrderedDict
25 from orddicts
import DefaultOrderedDict
28 (
"latitude",
"float"),
29 (
"longitude",
"float"),
30 (
"datetime",
"string")
35 'A':
"aerosol_optical_depth",
39 'converter': os.path.basename(__file__),
44 def __init__(self, filenames, obs_time, writer):
48 self.
varDictvarDict = defaultdict(
lambda: defaultdict(dict))
57 for ncvar, iodavar
in obsvars.items():
58 self.
varDictvarDict[iodavar][
'valKey'] = iodavar, self.
writerwriter.OvalName()
59 self.
varDictvarDict[iodavar][
'errKey'] = iodavar, self.
writerwriter.OerrName()
60 self.
varDictvarDict[iodavar][
'qcKey'] = iodavar, self.
writerwriter.OqcName()
65 ncd = nc.Dataset(f,
'r')
67 if 'Terra' in ncd_str:
68 AttrData[
'platform'] =
'Terra'
69 elif 'Aqua' in ncd_str:
70 AttrData[
'platform'] =
'Aqua'
71 if 'MODIS' in ncd_str:
72 AttrData[
'sensor'] =
'v.modis_terra'
75 AttrData[
'date_time'] = self.
obs_timeobs_time
76 AttrData[
'observation_type'] =
'Aod'
79 modis_time = ncd.variables[
'Scan_Start_Time'][:].ravel()
82 lats = ncd.variables[
'Latitude'][:].ravel()
83 lats = lats.astype(
'float32')
84 lons = ncd.variables[
'Longitude'][:].ravel()
85 lons = lons.astype(
'float32')
86 aod = ncd.variables[
'AOD_550_Dark_Target_Deep_Blue_Combined'][:].ravel()
87 land_sea_flag = ncd.variables[
'Land_sea_Flag'][:].ravel()
88 QC_flag = ncd.variables[
'Land_Ocean_Quality_Flag'][:].ravel()
89 QC_flag = QC_flag.astype(
'int8')
90 sol_zen = ncd.variables[
'Solar_Zenith'][:].ravel()
91 sen_zen = ncd.variables[
'Sensor_Zenith'][:].ravel()
92 unc_land = ncd.variables[
'Deep_Blue_Aerosol_Optical_Depth_550_Land_Estimated_Uncertainty'][:].ravel()
95 pos_index = np.where(aod > 0)
96 lats = lats[pos_index]
97 lons = lons[pos_index]
99 land_sea_flag = land_sea_flag[pos_index]
100 QC_flag = QC_flag[pos_index]
101 sol_zen = sol_zen[pos_index]
102 sen_zen = sen_zen[pos_index]
103 unc_land = unc_land[pos_index]
104 modis_time = modis_time[pos_index]
105 obs_time_2 = [datetime.fromisoformat(
'1993-01-01') + timedelta(seconds=x)
for x
in modis_time]
106 obs_time = [t.strftime(
'%Y-%m-%dT%H:%M:%SZ')
for t
in obs_time_2]
112 over_ocean = np.logical_not(land_sea_flag > 0)
113 over_land = np.logical_not(land_sea_flag == 0)
114 UNC = np.where(over_land, unc_land, np.add(0.05, np.multiply(0.15, aod)))
117 self.
loc_mdataloc_mdata[
'latitude'] = lats
118 self.
loc_mdataloc_mdata[
'longitude'] = lons
119 self.
loc_mdataloc_mdata[
'datetime'] = self.
writerwriter.FillNcVector(obs_time,
"datetime")
121 self.
loc_mdataloc_mdata[
'latitude'] = np.concatenate((self.
loc_mdataloc_mdata[
'latitude'], lats))
122 self.
loc_mdataloc_mdata[
'longitude'] = np.concatenate((self.
loc_mdataloc_mdata[
'longitude'], lons))
123 self.
loc_mdataloc_mdata[
'datetime'] = np.concatenate((self.
loc_mdataloc_mdata[
'datetime'], self.
writerwriter.FillNcVector(obs_time,
"datetime")))
125 for ncvar, iodavar
in obsvars.items():
126 data = aod.astype(
'float32')
129 self.
outdataoutdata[self.
varDictvarDict[iodavar][
'valKey']] = data
131 self.
outdataoutdata[self.
varDictvarDict[iodavar][
'qcKey']] = QC_flag
134 self.
outdataoutdata[self.
varDictvarDict[iodavar][
'valKey']] = np.concatenate(
135 (self.
outdataoutdata[self.
varDictvarDict[iodavar][
'valKey']], data))
136 self.
outdataoutdata[self.
varDictvarDict[iodavar][
'errKey']] = np.concatenate(
137 (self.
outdataoutdata[self.
varDictvarDict[iodavar][
'errKey']], err))
138 self.
outdataoutdata[self.
varDictvarDict[iodavar][
'qcKey']] = np.concatenate(
139 (self.
outdataoutdata[self.
varDictvarDict[iodavar][
'qcKey']], QC_flag))
142 self.
writerwriter._nvars = len(obsvars)
153 parser = argparse.ArgumentParser(
155 'Reads MODIS AOD hdf4 files provided by NASA'
156 ' and converts into IODA formatted output files. Multiple'
157 ' files are able to be concatenated.')
160 required = parser.add_argument_group(title=
'required arguments')
161 required.add_argument(
163 help=
"path of MODIS AOD hdf4 input file(s)",
164 type=str, nargs=
'+', required=
True)
165 required.add_argument(
167 help=
"Observation time in global attributes (YYYYMMDDHH)",
168 type=int, required=
True)
169 required.add_argument(
171 help=
"path of IODA output file",
172 type=str, required=
True)
174 args = parser.parse_args()
177 writer = iconv.NcWriter(args.output, locationKeyList)
183 aod_class =
AOD(args.input, args.time, writer)
185 original_stdout = sys.stdout
186 writer.BuildNetcdf(aod_class.outdata, aod_class.loc_mdata, aod_class.var_mdata, AttrData)
189 if __name__ ==
'__main__':
def __init__(self, filenames, obs_time, writer)