Skip to content

Commit 4c31171

Browse files
authored
DAS-2292: add SPL2SMAP collection to the SMAP-L2-Gridder (#13)
1 parent 51b0dbc commit 4c31171

File tree

17 files changed

+656
-112
lines changed

17 files changed

+656
-112
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
**/__pycache__
22
/.coverage
33
/reports/
4+
/workdir/

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [v0.1.0] - 2025-01-21
9+
10+
### Added
11+
12+
- Adds support for SPL2SMAP ([SMAP L2 Radar/Radiometer Half-Orbit 9 km EASE-Grid Soil Moisture](https://nsidc.org/data/spl2smap/versions/3)).
13+
- Removes `tb_time_utc` variables from SPL2SMP_E output.
14+
15+
816
## [v0.0.4] - 2024-12-04
917

1018
### Changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This repository contains the code for the Harmony-SMAP-L2-Gridding-Service, which is a python service that transforms NASA level 2 gridded trajectory data into gridded NetCDF4-CF output files.
44

5-
This code currently works on `SPL2SMP_E` data and will be adapted for other SMAP collections of gridded trajectory data.
5+
This code currently works on `SPL2SMP_E`, and `SPL2SMAP` data and will be adapted for other SMAP collections [`SPL2SMP`,`SPL2SMA`] of gridded trajectory data.
66

77

88
## Transforming Data

docker/service_version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.4
1+
0.1.0

harmony_service/adapter.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ def process_item(self, item: Item, source: HarmonySource) -> Item:
5050
asset.href, is_regridded=True, ext='.nc'
5151
)
5252

53-
transform_l2g_input(
54-
input_filepath, working_filename, logger=self.logger
55-
)
53+
transform_l2g_input(input_filepath, working_filename)
5654

5755
# Stage the transformed output:
5856
staged_url = stage(

pip_requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ harmony-service-lib==2.3.0
22
netcdf4==1.7.2
33
pyproj==3.7.0
44
pystac==1.11.0
5-
xarray==2024.10.0
5+
xarray==2025.1.1

smap_l2_gridder/collections.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"""Collection information.
2+
3+
Defines hierarchies necessary for gridding collections with the SMAP L2 Gridder.
4+
5+
While the input files are hierarchical and in hdf format, they are not fully
6+
self describing. Each griddable variable is tied to two variables that contain
7+
the column and row of a grid into which the value should be placed. But these
8+
column and row indices are not always in the same location. Additionally,
9+
there are a number of different resolution grids and coordinate reference
10+
systems, that here are identified by a gpd file and epsg code that are
11+
described in the documentation for the dataset but are hard/impossible to
12+
determine by looking at the files themselves, for this reason we explictly lay
13+
out this information in this file along with helper routines to ease access.
14+
15+
"""
16+
17+
from .exceptions import InvalidCollectionError
18+
19+
STANDARD_LOCATIONS = {
20+
'row': 'Soil_Moisture_Retrieval_Data/EASE_row_index',
21+
'col': 'Soil_Moisture_Retrieval_Data/EASE_column_index',
22+
}
23+
24+
GRIDS = {
25+
'M03km': {'gpd': 'EASE2_M03km.gpd', 'epsg': 'EPSG:6933'},
26+
'M09km': {'gpd': 'EASE2_M09km.gpd', 'epsg': 'EPSG:6933'},
27+
'M36km': {'gpd': 'EASE2_M36km.gpd', 'epsg': 'EPSG:6933'},
28+
'N09km': {'gpd': 'EASE2_N09km.gpd', 'epsg': 'EPSG:6931'},
29+
}
30+
31+
32+
COLLECTION_INFORMATION = {
33+
'SPL2SMP_E': {
34+
'metadata': ['Metadata'],
35+
'data_groups': {
36+
'Soil_Moisture_Retrieval_Data': {
37+
**STANDARD_LOCATIONS,
38+
**GRIDS['M09km'],
39+
'dropped_variables': ['tb_time_utc'],
40+
},
41+
'Soil_Moisture_Retrieval_Data_Polar': {
42+
'row': 'Soil_Moisture_Retrieval_Data_Polar/EASE_row_index',
43+
'col': 'Soil_Moisture_Retrieval_Data_Polar/EASE_column_index',
44+
**GRIDS['N09km'],
45+
'dropped_variables': ['tb_time_utc'],
46+
},
47+
},
48+
},
49+
'SPL2SMAP': {
50+
'metadata': ['Metadata'],
51+
'data_groups': {
52+
'Soil_Moisture_Retrieval_Data': {
53+
**STANDARD_LOCATIONS,
54+
**GRIDS['M09km'],
55+
'dropped_variables': ['spacecraft_overpass_time_utc'],
56+
},
57+
'Soil_Moisture_Retrieval_Data_3km': {
58+
'row': 'Soil_Moisture_Retrieval_Data_3km/EASE_row_index_3km',
59+
'col': 'Soil_Moisture_Retrieval_Data_3km/EASE_column_index_3km',
60+
**GRIDS['M03km'],
61+
'dropped_variables': ['spacecraft_overpass_time_utc'],
62+
},
63+
},
64+
},
65+
'SPL2SMA': {
66+
'metadata': ['Metadata'],
67+
'data_groups': {
68+
'Ancillary_Data': {**STANDARD_LOCATIONS, **GRIDS['M03km']},
69+
'Radar_Data': {**STANDARD_LOCATIONS, **GRIDS['M03km']},
70+
'Soil_Moisture_Retrieval_Data': {**STANDARD_LOCATIONS, **GRIDS['M03km']},
71+
},
72+
},
73+
'SPL2SMP': {
74+
'metadata': ['Metadata'],
75+
'data_groups': {
76+
'Soil_Moisture_Retrieval_Data': {
77+
**STANDARD_LOCATIONS,
78+
**GRIDS['M36km'],
79+
}
80+
},
81+
},
82+
}
83+
84+
85+
def get_all_information() -> dict:
86+
"""Returns all known collection information.
87+
88+
Mostly exists to mock tests.
89+
"""
90+
return COLLECTION_INFORMATION
91+
92+
93+
def get_collection_info(short_name: str) -> dict:
94+
"""Return the configuration information for the short_name's collection."""
95+
try:
96+
return get_all_information()[short_name]
97+
except KeyError as exc:
98+
raise InvalidCollectionError(
99+
f'No collection information for {short_name}'
100+
) from exc
101+
102+
103+
def get_collection_group_info(short_name: str, group: str) -> dict:
104+
"""Get basic information for a collection's group.
105+
106+
Helper function to identify which information was incorrect when attempting
107+
to retrieve the desired gridding information
108+
109+
"""
110+
collection = get_collection_info(short_name)
111+
try:
112+
group_info = collection['data_groups'][group]
113+
except KeyError as exc:
114+
raise InvalidCollectionError(f'No group named {group} in {short_name}') from exc
115+
116+
return group_info
117+
118+
119+
def get_dropped_variables(short_name: str, group: str) -> set[str]:
120+
"""Return a set of variables to be excluded from the processed file."""
121+
try:
122+
info = get_collection_group_info(short_name, group)
123+
dropped_vars = info['dropped_variables']
124+
return set(dropped_vars)
125+
except KeyError:
126+
return set()

smap_l2_gridder/crs.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,6 @@ def col_row_to_xy(self, col: int, row: int) -> tuple[np.float64, np.float64]:
3838
return x, y
3939

4040

41-
# NSIDC EASE-Grid 2.0 Global CRS definition
42-
# from: https://epsg.org/crs/wkt/id/6933
43-
EPSG_6933_WKT = CRS.from_epsg(6933).to_wkt()
44-
45-
# NSIDC EASE-Grid 2.0 North CRS definition
46-
# from: https://epsg.org/crs/wkt/id/6931
47-
EPSG_6931_WKT = CRS.from_epsg(6931).to_wkt()
48-
49-
5041
def geotransform_from_target_info(target_info: dict) -> Geotransform:
5142
"""Return a geotransform from the grid_info dict.
5243

smap_l2_gridder/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ def __init__(self, message=None):
1111

1212
class InvalidGPDError(SMAPL2GridderError):
1313
"""Raised if an invalid GPD is used."""
14+
15+
16+
class InvalidCollectionError(SMAPL2GridderError):
17+
"""Raised when attempting operations on invalid collections."""

0 commit comments

Comments
 (0)