IODA Bundle
smos_ssm2ioda.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 #
3 # (C) Copyright 2021 NOAA/NWS/NCEP/EMC
4 #
5 # This software is licensed under the terms of the Apache Licence Version 2.0
6 # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
7 #
8 import sys, os
9 import argparse
10 import netCDF4 as nc
11 import numpy as np
12 from datetime import datetime, timedelta
13 from pathlib import Path
14 
15 IODA_CONV_PATH = Path(__file__).parent/"@SCRIPT_LIB_PATH@"
16 if not IODA_CONV_PATH.is_dir():
17  IODA_CONV_PATH = Path(__file__).parent/'..'/'lib-python'
18 sys.path.append(str(IODA_CONV_PATH.resolve()))
19 
20 import ioda_conv_ncio as iconv
21 from collections import defaultdict, OrderedDict
22 from orddicts import DefaultOrderedDict
23 
24 locationKeyList = [
25  ("latitude", "float"),
26  ("longitude", "float"),
27  ("datetime", "string")
28 ]
29 
30 obsvars = {
31  'soil_moisture': 'soilMoistureVolumetric',
32 }
33 
34 AttrData = {
35  'converter': os.path.basename(__file__),
36 }
37 
38 
39 class SMOS_L2NRT(object):
40 
41  def __init__(self, filename, mask, writer):
42  self.filenamefilename = filename
43  self.maskmask = mask
44  self.writerwriter = writer
45  self.varDictvarDict = defaultdict(lambda: defaultdict(dict))
46  self.outdataoutdata = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
47  self.loc_mdataloc_mdata = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
48  self.var_mdatavar_mdata = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
49  self.unitsunits = {}
50  self._read_read()
51 
52  def _read(self):
53 
54  # set up variable names for IODA
55  for iodavar in ['soilMoistureVolumetric']:
56  self.varDictvarDict[iodavar]['valKey'] = iodavar, self.writerwriter.OvalName()
57  self.varDictvarDict[iodavar]['errKey'] = iodavar, self.writerwriter.OerrName()
58  self.varDictvarDict[iodavar]['qcKey'] = iodavar, self.writerwriter.OqcName()
59  self.unitsunits[iodavar] = 'm3m-3'
60  # open input file name
61  ncd = nc.Dataset(self.filenamefilename, 'r')
62  # set and get global attributes
63  AttrData["observation_type"] = "surface soil moisture"
64  AttrData["satellite"] = "SMOS"
65  AttrData["sensor"] = "MIRAS"
66 
67  lons = ncd.variables['longitude'][:]
68  lats = ncd.variables['latitude'][:]
69  vals = ncd.variables['soil_moisture'][:]
70  errs = ncd.variables['soil_moisture_uncertainty'][:]
71  rfip = ncd.variables['RFI_probability'][:]
72  ddys = ncd.variables['days_since_01-01-2000'][:]
73  secs = ncd.variables['seconds_since_midnight'][:]
74  times = np.empty_like(vals, dtype=object)
75 
76  qflg = rfip.astype('int32')
77 
78  if self.maskmask == "maskout":
79  mask = vals >= 0.0
80  vals = vals[mask]
81  lons = lons[mask]
82  lats = lats[mask]
83  errs = errs[mask]
84  qflg = qflg[mask]
85  ddys = ddys[mask]
86  secs = secs[mask]
87  times = times[mask]
88  ncd.close()
89 
90  for i in range(len(lons)):
91 
92  # defined QC flag(Kerr et al., 2016)
93  if rfip[i] > 20.0:
94  qflg[i] = 1
95  else:
96  qflg[i] = 0
97 
98  base_date = datetime(2000, 1, 1) + timedelta(days=int(ddys[i]))
99  dt = base_date + timedelta(seconds=int(secs[i]))
100  base_datetime = dt.strftime("%Y-%m-%dT%H:%M:%SZ")
101  AttrData['date_time_string'] = base_datetime
102  times[i] = base_datetime
103 
104  self.loc_mdataloc_mdata['datetime'] = self.writerwriter.FillNcVector(times, "datetime")
105  self.loc_mdataloc_mdata['latitude'] = lats
106  self.loc_mdataloc_mdata['longitude'] = lons
107  for iodavar in ['soilMoistureVolumetric']:
108  self.outdataoutdata[self.varDictvarDict[iodavar]['valKey']] = vals
109  self.outdataoutdata[self.varDictvarDict[iodavar]['errKey']] = errs
110  self.outdataoutdata[self.varDictvarDict[iodavar]['qcKey']] = qflg
111  self.writerwriter._nvars = len(obsvars)
112  self.writerwriter._nlocs = len(self.loc_mdataloc_mdata['datetime'])
113 
114 
115 def main():
116 
117  parser = argparse.ArgumentParser(
118  description=('Read SMOS surface soil moisture file(s) and Converter'
119  ' of native NetCDF format for observations of soil'
120  ' moisture from SMOS to IODA netCDF format.')
121  )
122  parser.add_argument('-i', '--input',
123  help="name of smos soil moisture input file(s)",
124  type=str, required=True)
125  parser.add_argument('-o', '--output',
126  help="name of ioda output file",
127  type=str, required=True)
128  optional = parser.add_argument_group(title='optional arguments')
129  optional.add_argument(
130  '-m', '--mask',
131  help="maskout missing values: maskout/default, default=none",
132  type=str, required=True)
133 
134  args = parser.parse_args()
135 
136  writer = iconv.NcWriter(args.output, locationKeyList)
137 
138  # Read in the profiles
139  ssm = SMOS_L2NRT(args.input, args.mask, writer)
140 
141  # write everything out
142  writer.BuildNetcdf(ssm.outdata, ssm.loc_mdata, ssm.var_mdata, AttrData, ssm.units)
143 
144 
145 if __name__ == '__main__':
146  main()
def __init__(self, filename, mask, writer)