17 from datetime
import datetime
18 from argparse
import ArgumentParser, ArgumentDefaultsHelpFormatter
19 from pathlib
import Path
23 IODA_CONV_PATH = Path(__file__).parent/
"@SCRIPT_LIB_PATH@"
24 if not IODA_CONV_PATH.is_dir():
25 IODA_CONV_PATH = Path(__file__).parent/
'..'/
'lib-python'
26 sys.path.append(
str(IODA_CONV_PATH.resolve()))
29 import ioda_conv_ncio
as iconv
30 from orddicts
import DefaultOrderedDict
32 os.environ[
"TZ"] =
"UTC"
42 self.
float_fillfloat_fill = netCDF4.default_fillvals[
'f4']
58 data[
'ob_datetime'] = []
68 Read in the METARs data
69 Header contains: Unix_time,DateString,ICAO,Latitude,Longitude,Elev,Temp,Dewp,Wdir,Wspd,Wgst,Vis,\
70 Pcp,Pcp3h,Pcp6h,Pcp24h,QcFlag,WxString,WxCode,Altimeter,Cvg1,Bas1,Cvg2,Bas2,Cvg3,Bas3,Length,Raw
74 with open(self.
filenamefilename,
'r')
as fh:
76 csv_dict_reader = csv.DictReader(fh)
77 column_names = csv_dict_reader.fieldnames
80 for row
in csv_dict_reader:
86 icao =
str(row[
'ICAO'])
88 utime =
int(row[
'Unix_time'])
89 lat = float(row[
'Latitude'])
90 lon = float(row[
'Longitude'])
91 elev = float(row[
'Elev'])
92 if (elev < -999
or elev > 8450):
97 except (csv.Error, ValueError):
100 temp = float(row[
'Temp']) + self.
meteo_utilsmeteo_utils.C_2_K
101 except (csv.Error, ValueError):
104 dewp = float(row[
'Dewp']) + self.
meteo_utilsmeteo_utils.C_2_K
105 except (csv.Error, ValueError):
108 wdir = float(row[
'Wdir'])
109 except (csv.Error, ValueError):
112 wspd = float(row[
'Wspd']) * self.
meteo_utilsmeteo_utils.KTS_2_MS
113 except (csv.Error, ValueError):
117 if (wdir == 0
and wspd == 0):
120 elif (wdir > 0
and wdir <= 360
and wspd > 0):
121 uwnd, vwnd = self.
meteo_utilsmeteo_utils.dir_speed_2_uv(wdir, wspd)
130 altim = float(row[
'Altimeter'])
131 psfc = self.
meteo_utilsmeteo_utils.altim_2_sfcPressure(altim, elev)
132 except (csv.Error, ValueError):
137 spfh = self.
meteo_utilsmeteo_utils.specific_humidity(dewp, psfc)
141 data[
'ob_icao'].append(icao)
142 data[
'ob_time'].append(utime)
143 data[
'ob_datetime'].append(datetime.fromtimestamp(utime).strftime(
"%Y-%m-%dT%H:%M:%SZ"))
144 data[
'ob_lat'].append(lat)
145 data[
'ob_lon'].append(lon)
146 data[
'ob_elev'].append(elev)
147 data[
'ob_hght'].append(hght)
148 data[
'ob_psfc'].append(psfc)
149 data[
'ob_temp'].append(temp)
150 data[
'ob_spfh'].append(spfh)
151 data[
'ob_uwnd'].append(uwnd)
152 data[
'ob_vwnd'].append(vwnd)
162 def __init__(self, filename, date, varDict, obsList):
164 Initialize IODA writer class,
165 transform to IODA data structure and,
166 write out to IODA file.
174 (
"station_id",
"string"),
175 (
"latitude",
"float"),
176 (
"longitude",
"float"),
177 (
"station_elevation",
"float"),
179 (
"datetime",
"string")
184 'date_time_string': self.
datedate.strftime(
"%Y-%m-%dT%H:%M:%SZ")
190 for key
in self.
varDictvarDict.keys():
191 value = self.
varDictvarDict[key]
192 self.
keyDictkeyDict[key][
'valKey'] = value, self.
writerwriter.OvalName()
193 self.
keyDictkeyDict[key][
'errKey'] = value, self.
writerwriter.OerrName()
194 self.
keyDictkeyDict[key][
'qcKey'] = value, self.
writerwriter.OqcName()
203 for n
in range(len(obs.data[
'ob_lat'])):
205 icao = obs.data[
'ob_icao'][n]
206 lat = obs.data[
'ob_lat'][n]
207 lon = obs.data[
'ob_lon'][n]
208 elev = obs.data[
'ob_elev'][n]
209 hght = obs.data[
'ob_hght'][n]
210 dtg = obs.data[
'ob_datetime'][n]
211 locKey = icao, lat, lon, elev, hght, dtg
215 for key
in self.
varDictvarDict.keys():
217 val = obs.data[key][n]
221 valKey = self.
keyDictkeyDict[key][
'valKey']
222 errKey = self.
keyDictkeyDict[key][
'errKey']
223 qcKey = self.
keyDictkeyDict[key][
'qcKey']
225 self.
datadata[recKey][locKey][valKey] = val
226 self.
datadata[recKey][locKey][errKey] = err
227 self.
datadata[recKey][locKey][qcKey] = qc
231 (ObsVars, LocMdata, VarMdata) = self.
writerwriter.ExtractObsData(self.
datadata)
232 self.
writerwriter.BuildNetcdf(ObsVars, LocMdata, VarMdata, self.
AttrDataAttrData)
239 desc =
'Convert CSV-formatted METAR data to IODA netCDF4 format'
240 parser = ArgumentParser(
242 formatter_class=ArgumentDefaultsHelpFormatter)
244 '-i',
'--input', help=
'name of the input METARs CSV-formatted file',
245 type=str, nargs=
'+', required=
True)
247 '-o',
'--output', help=
'name of the output netCDF IODA-ready file',
248 type=str, required=
True, default=
None)
250 '-d',
'--date', help=
'file date', metavar=
'YYYYMMDDHH',
251 type=str, required=
True)
253 args = parser.parse_args()
256 foutput = args.output
257 fdate = datetime.strptime(args.date,
'%Y%m%d%H')
265 'ob_temp':
'air_temperature',
266 'ob_spfh':
'specific_humidity',
267 'ob_psfc':
'surface_pressure',
268 'ob_uwnd':
'eastward_wind',
269 'ob_vwnd':
'northward_wind'
272 IODA(foutput, fdate, varDict, obsList)
275 if __name__ ==
'__main__':