Skip to content

Commit

Permalink
DAS-2292: add SPL2SMAP collection to the SMAP-L2-Gridder (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
flamingbear authored Jan 30, 2025
1 parent 51b0dbc commit 4c31171
Show file tree
Hide file tree
Showing 17 changed files with 656 additions and 112 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/__pycache__
/.coverage
/reports/
/workdir/
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.1.0] - 2025-01-21

### Added

- Adds support for SPL2SMAP ([SMAP L2 Radar/Radiometer Half-Orbit 9 km EASE-Grid Soil Moisture](https://nsidc.org/data/spl2smap/versions/3)).
- Removes `tb_time_utc` variables from SPL2SMP_E output.


## [v0.0.4] - 2024-12-04

### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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.

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


## Transforming Data
Expand Down
2 changes: 1 addition & 1 deletion docker/service_version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.4
0.1.0
4 changes: 1 addition & 3 deletions harmony_service/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ def process_item(self, item: Item, source: HarmonySource) -> Item:
asset.href, is_regridded=True, ext='.nc'
)

transform_l2g_input(
input_filepath, working_filename, logger=self.logger
)
transform_l2g_input(input_filepath, working_filename)

# Stage the transformed output:
staged_url = stage(
Expand Down
2 changes: 1 addition & 1 deletion pip_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ harmony-service-lib==2.3.0
netcdf4==1.7.2
pyproj==3.7.0
pystac==1.11.0
xarray==2024.10.0
xarray==2025.1.1
126 changes: 126 additions & 0 deletions smap_l2_gridder/collections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"""Collection information.
Defines hierarchies necessary for gridding collections with the SMAP L2 Gridder.
While the input files are hierarchical and in hdf format, they are not fully
self describing. Each griddable variable is tied to two variables that contain
the column and row of a grid into which the value should be placed. But these
column and row indices are not always in the same location. Additionally,
there are a number of different resolution grids and coordinate reference
systems, that here are identified by a gpd file and epsg code that are
described in the documentation for the dataset but are hard/impossible to
determine by looking at the files themselves, for this reason we explictly lay
out this information in this file along with helper routines to ease access.
"""

from .exceptions import InvalidCollectionError

STANDARD_LOCATIONS = {
'row': 'Soil_Moisture_Retrieval_Data/EASE_row_index',
'col': 'Soil_Moisture_Retrieval_Data/EASE_column_index',
}

GRIDS = {
'M03km': {'gpd': 'EASE2_M03km.gpd', 'epsg': 'EPSG:6933'},
'M09km': {'gpd': 'EASE2_M09km.gpd', 'epsg': 'EPSG:6933'},
'M36km': {'gpd': 'EASE2_M36km.gpd', 'epsg': 'EPSG:6933'},
'N09km': {'gpd': 'EASE2_N09km.gpd', 'epsg': 'EPSG:6931'},
}


COLLECTION_INFORMATION = {
'SPL2SMP_E': {
'metadata': ['Metadata'],
'data_groups': {
'Soil_Moisture_Retrieval_Data': {
**STANDARD_LOCATIONS,
**GRIDS['M09km'],
'dropped_variables': ['tb_time_utc'],
},
'Soil_Moisture_Retrieval_Data_Polar': {
'row': 'Soil_Moisture_Retrieval_Data_Polar/EASE_row_index',
'col': 'Soil_Moisture_Retrieval_Data_Polar/EASE_column_index',
**GRIDS['N09km'],
'dropped_variables': ['tb_time_utc'],
},
},
},
'SPL2SMAP': {
'metadata': ['Metadata'],
'data_groups': {
'Soil_Moisture_Retrieval_Data': {
**STANDARD_LOCATIONS,
**GRIDS['M09km'],
'dropped_variables': ['spacecraft_overpass_time_utc'],
},
'Soil_Moisture_Retrieval_Data_3km': {
'row': 'Soil_Moisture_Retrieval_Data_3km/EASE_row_index_3km',
'col': 'Soil_Moisture_Retrieval_Data_3km/EASE_column_index_3km',
**GRIDS['M03km'],
'dropped_variables': ['spacecraft_overpass_time_utc'],
},
},
},
'SPL2SMA': {
'metadata': ['Metadata'],
'data_groups': {
'Ancillary_Data': {**STANDARD_LOCATIONS, **GRIDS['M03km']},
'Radar_Data': {**STANDARD_LOCATIONS, **GRIDS['M03km']},
'Soil_Moisture_Retrieval_Data': {**STANDARD_LOCATIONS, **GRIDS['M03km']},
},
},
'SPL2SMP': {
'metadata': ['Metadata'],
'data_groups': {
'Soil_Moisture_Retrieval_Data': {
**STANDARD_LOCATIONS,
**GRIDS['M36km'],
}
},
},
}


def get_all_information() -> dict:
"""Returns all known collection information.
Mostly exists to mock tests.
"""
return COLLECTION_INFORMATION


def get_collection_info(short_name: str) -> dict:
"""Return the configuration information for the short_name's collection."""
try:
return get_all_information()[short_name]
except KeyError as exc:
raise InvalidCollectionError(
f'No collection information for {short_name}'
) from exc


def get_collection_group_info(short_name: str, group: str) -> dict:
"""Get basic information for a collection's group.
Helper function to identify which information was incorrect when attempting
to retrieve the desired gridding information
"""
collection = get_collection_info(short_name)
try:
group_info = collection['data_groups'][group]
except KeyError as exc:
raise InvalidCollectionError(f'No group named {group} in {short_name}') from exc

return group_info


def get_dropped_variables(short_name: str, group: str) -> set[str]:
"""Return a set of variables to be excluded from the processed file."""
try:
info = get_collection_group_info(short_name, group)
dropped_vars = info['dropped_variables']
return set(dropped_vars)
except KeyError:
return set()
9 changes: 0 additions & 9 deletions smap_l2_gridder/crs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ def col_row_to_xy(self, col: int, row: int) -> tuple[np.float64, np.float64]:
return x, y


# NSIDC EASE-Grid 2.0 Global CRS definition
# from: https://epsg.org/crs/wkt/id/6933
EPSG_6933_WKT = CRS.from_epsg(6933).to_wkt()

# NSIDC EASE-Grid 2.0 North CRS definition
# from: https://epsg.org/crs/wkt/id/6931
EPSG_6931_WKT = CRS.from_epsg(6931).to_wkt()


def geotransform_from_target_info(target_info: dict) -> Geotransform:
"""Return a geotransform from the grid_info dict.
Expand Down
4 changes: 4 additions & 0 deletions smap_l2_gridder/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ def __init__(self, message=None):

class InvalidGPDError(SMAPL2GridderError):
"""Raised if an invalid GPD is used."""


class InvalidCollectionError(SMAPL2GridderError):
"""Raised when attempting operations on invalid collections."""
Loading

0 comments on commit 4c31171

Please sign in to comment.