Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,15 @@ In the test case, YYYYMMDD is set 20200228. For -i you can specify an input file

For surface volumetric soil moisture (ssm), SMAP NRT h5 files are supported with `smap_ssm2ioda.py`.
```
Usage: smap_ssm2ioda.py -i input_smap_file.h5 -o output_ioda_file.nc -m maskout
Usage: smap_ssm2ioda.py -i input_smap_file.h5 -o output_ioda_file.nc --maskMissing
```
For -i you can specify an input file and the converter will write it to one output file. For maskout option (-m) default/maskout, default means to keep all missing values and maskout means to not write out missing values. It should be noted that SMAP NRT h5 filename contains date and time which has been transferred to the datetime in smap_ssm2ioda.py because the data in the file does not have date and time variables. The h5 file is read with the netCDF4 module rather than the h5py module generally used.
For -i you can specify an input file and the converter will write it to one output file. --maskMissing means to not write out missing values. It should be noted that SMAP NRT h5 filename contains date and time which has been transferred to the datetime in smap_ssm2ioda.py because the data in the file does not have date and time variables. The h5 file is read with the netCDF4 module rather than the h5py module generally used.

For surface volumetric soil moisture (ssm), SMAP 9km h5 files are supported with `smap9km_ssm2ioda.py`.
```
Usage: smap9km_ssm2ioda.py -i input_smap9km_file.h5 -o output_ioda_file.nc --maskMissing
```
For -i you can specify an input file and the converter will write it to one output file. --maskMissin means to not write out missing values. The h5 file is read with the netCDF4 module rather than the h5py module generally used.

For surface volumetric soil moisture (ssm), SMOS L2 NRT Netcdf files are supported with `smos_ssm2ioda.py`.
```
Expand Down
27 changes: 19 additions & 8 deletions src/land/smap9km_ssm2ioda.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
locationKeyList = [
("latitude", "float"),
("longitude", "float"),
("depthBelowSoilSurface", "float"),
("datetime", "string")
]

Expand All @@ -45,9 +46,10 @@


class smap(object):
def __init__(self, filename, mask):
self.filename = filename
self.mask = mask
def __init__(self, args):
self.filename = args.input
self.mask = args.maskMissing
self.assumedSoilDepth = args.assumedSoilDepth
self.varDict = defaultdict(lambda: defaultdict(dict))
self.outdata = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
self.varAttrs = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
Expand Down Expand Up @@ -92,14 +94,16 @@ def _read(self):
ecoli = ncd.groups['Soil_Moisture_Retrieval_Data'].variables['EASE_column_index'][:].ravel()
refsec = ncd.groups['Soil_Moisture_Retrieval_Data'].variables['tb_time_seconds'][:].ravel()

deps = np.full_like(vals, self.assumedSoilDepth)
times = np.empty_like(vals, dtype=object)

if self.mask == "maskout":
if self.mask:
with np.errstate(invalid='ignore'):
mask = (vals > valid_min) & (vals < valid_max)
vals = vals[mask]
lats = lats[mask]
lons = lons[mask]
deps = deps[mask]
errs = errs[mask]
qflg = qflg[mask]
sflg = sflg[mask]
Expand All @@ -114,6 +118,7 @@ def _read(self):
vals = vals.astype('float32')
lats = lats.astype('float32')
lons = lons.astype('float32')
deps = deps.astype('float32')
errs = errs.astype('float32')
qflg = qflg.astype('int32')
sflg = sflg.astype('int32')
Expand All @@ -131,6 +136,8 @@ def _read(self):
self.outdata[('longitude', 'MetaData')] = lons
self.varAttrs[('latitude', 'MetaData')]['units'] = 'degree_north'
self.varAttrs[('longitude', 'MetaData')]['units'] = 'degree_east'
self.outdata[('depthBelowSoilSurface', 'MetaData')] = deps
self.varAttrs[('depthBelowSoilSurface', 'MetaData')]['units'] = 'm'
self.outdata[('surfaceFlag', 'MetaData')] = sflg
self.varAttrs[('surfaceFlag', 'MetaData')]['units'] = 'unitless'
self.outdata[('vegetationOpacity', 'MetaData')] = vegop
Expand Down Expand Up @@ -165,14 +172,18 @@ def main():
type=str, required=True)
optional = parser.add_argument_group(title='optional arguments')
optional.add_argument(
'-m', '--mask',
help="maskout missing values: maskout/default, default=none",
type=str, required=True)
'-m', '--maskMissing',
help="switch to mask missing values: default=False",
default=False, action='store_true', required=False)
optional.add_argument(
'-d', '--assumedSoilDepth',
help="default assumed depth of soil moisture in meters",
type=float, default=0.025, required=False)

args = parser.parse_args()

# Read in the SMAP volumetric soil moisture data
ssm = smap(args.input, args.mask)
ssm = smap(args)

# setup the IODA writer
writer = iconv.IodaWriter(args.output, locationKeyList, DimDict)
Expand Down
28 changes: 20 additions & 8 deletions src/land/smap_ssm2ioda.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
locationKeyList = [
("latitude", "float"),
("longitude", "float"),
("depthBelowSoilSurface", "float"),
("datetime", "string")
]

Expand All @@ -45,9 +46,10 @@


class smap(object):
def __init__(self, filename, mask):
self.filename = filename
self.mask = mask
def __init__(self, args):
self.filename = args.input
self.mask = args.maskMissing
self.assumedSoilDepth = args.assumedSoilDepth
self.varDict = defaultdict(lambda: defaultdict(dict))
self.outdata = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
self.varAttrs = defaultdict(lambda: DefaultOrderedDict(OrderedDict))
Expand Down Expand Up @@ -85,14 +87,17 @@ def _read(self):
lons = ncd.groups['Soil_Moisture_Retrieval_Data'].variables['longitude'][:].ravel()
errs = ncd.groups['Soil_Moisture_Retrieval_Data'].variables['soil_moisture_error'][:].ravel()
qflg = ncd.groups['Soil_Moisture_Retrieval_Data'].variables['retrieval_qual_flag'][:].ravel()

deps = np.full_like(vals, self.assumedSoilDepth)
times = np.empty_like(vals, dtype=object)

if self.mask == "maskout":
if self.mask:
with np.errstate(invalid='ignore'):
mask = (vals > valid_min) & (vals < valid_max)
vals = vals[mask]
lats = lats[mask]
lons = lons[mask]
deps = deps[mask]
errs = errs[mask]
qflg = qflg[mask]
times = times[mask]
Expand All @@ -105,6 +110,7 @@ def _read(self):
vals = vals.astype('float32')
lats = lats.astype('float32')
lons = lons.astype('float32')
deps = deps.astype('float32')
errs = errs.astype('float32')
qflg = qflg.astype('int32')
AttrData['date_time_string'] = base_datetime
Expand All @@ -127,6 +133,8 @@ def _read(self):
self.outdata[('datetime', 'MetaData')] = times
self.outdata[('latitude', 'MetaData')] = lats
self.outdata[('longitude', 'MetaData')] = lons
self.outdata[('depthBelowSoilSurface', 'MetaData')] = deps
self.varAttrs[('depthBelowSoilSurface', 'MetaData')]['units'] = 'm'

for iodavar in ['soilMoistureVolumetric']:
self.outdata[self.varDict[iodavar]['valKey']] = vals
Expand All @@ -152,14 +160,18 @@ def main():
type=str, required=True)
optional = parser.add_argument_group(title='optional arguments')
optional.add_argument(
'-m', '--mask',
help="maskout missing values: maskout/default, default=none",
type=str, required=True)
'-m', '--maskMissing',
help="switch to mask missing values: default=False",
default=False, action='store_true', required=False)
optional.add_argument(
'-d', '--assumedSoilDepth',
help="default assumed depth of soil moisture in meters",
type=float, default=0.025, required=False)

args = parser.parse_args()

# Read in the SMAP volumetric soil moisture data
ssm = smap(args.input, args.mask)
ssm = smap(args)

# setup the IODA writer
writer = iconv.IodaWriter(args.output, locationKeyList, DimDict)
Expand Down
4 changes: 2 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1698,7 +1698,7 @@ ecbuild_add_test( TARGET test_${PROJECT_NAME}_smap_ssm
"${Python3_EXECUTABLE} ${CMAKE_BINARY_DIR}/bin/smap_ssm2ioda.py
-i testinput/SMAP_L2_SM_P_NRT_24342_A_20190822T224858_N16023_002.h5
-o testrun/smap_ssm.nc
-m maskout"
--maskMissing"
smap_ssm.nc ${IODA_CONV_COMP_TOL_ZERO})

ecbuild_add_test( TARGET test_${PROJECT_NAME}_smos_ssm
Expand Down Expand Up @@ -1745,7 +1745,7 @@ ecbuild_add_test( TARGET test_${PROJECT_NAME}_smap9km_ssm
"${Python3_EXECUTABLE} ${CMAKE_BINARY_DIR}/bin/smap9km_ssm2ioda.py
-i testinput/SMAP_L2_SM_P_E_36365_D_20211122T013945_R18240_001.h5
-o testrun/smap9km_ssm.nc
-m maskout"
--maskMissing"
smap9km_ssm.nc ${IODA_CONV_COMP_TOL_ZERO})

ecbuild_add_test( TARGET test_${PROJECT_NAME}_land_owp_snow_obs_dup_thin
Expand Down
4 changes: 2 additions & 2 deletions test/testoutput/smap9km_ssm.nc
Git LFS file not shown
4 changes: 2 additions & 2 deletions test/testoutput/smap_ssm.nc
Git LFS file not shown