diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a18ed7..a10326a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## v1.1.0 +### 2024-09-10 + +This version of HOSS provides support for gridded products that do not contain CF-Convention +compliant grid mapping variables and 1-D dimension variables, such as SMAP L3. +New methods are added to retrieve dimension scales from coordinate attributes and grid mappings, using +overrides specified in the hoss_config.json configuration file. +- `get_coordinate_variables` gets coordinate datasets when the dimension scales are not present in + the source file. The prefetch gets the coordinate datasets during prefetch when the dimension + scales are not present. +- `update_dimension_variables` function checks the dimensionality of the coordinate datasets. + It then gets a row and column from the 2D datasets to 1D and uses the crs attribute to get + the projection of the granule to convert the lat/lon array to projected x-y dimension scales. +- `get_override_projected_dimensions` provides the projected dimension scale names after the + conversion. +- `get_variable_crs` method is also updated to handle cases where the grid mapping variable + does not exist in the granule and an override is provided in an updated + hoss_config.json + ## v1.0.5 ### 2024-08-19 diff --git a/docker/service_version.txt b/docker/service_version.txt index 90a27f9..9084fa2 100644 --- a/docker/service_version.txt +++ b/docker/service_version.txt @@ -1 +1 @@ -1.0.5 +1.1.0 diff --git a/docs/requirements.txt b/docs/requirements.txt index dd7a29c..700910c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -16,5 +16,5 @@ # harmony-py~=0.4.10 netCDF4~=1.6.4 -notebook~=7.0.4 +notebook~=7.2.2 xarray~=2023.9.0 diff --git a/hoss/coordinate_utilities.py b/hoss/coordinate_utilities.py new file mode 100644 index 0000000..ae5bfbe --- /dev/null +++ b/hoss/coordinate_utilities.py @@ -0,0 +1,425 @@ +""" This module contains utility functions used for + coordinate variables and methods to convert the + coordinate variable data to x/y dimension scales +""" + +from typing import Dict, Set, Tuple + +import numpy as np +from netCDF4 import Dataset +from numpy import ndarray +from pyproj import CRS, Transformer +from varinfo import VariableFromDmr, VarInfoFromDmr + +from hoss.exceptions import ( + CannotComputeDimensionResolution, + InvalidCoordinateVariable, + IrregularCoordinateVariables, + MissingCoordinateVariable, +) + + +def get_override_projected_dimension_name( + varinfo: VarInfoFromDmr, + variable_name: str, +) -> str: + """returns the x-y projection variable names that would + match the geo coordinate names. The `latitude` coordinate + variable name gets converted to 'projected_y' dimension scale + and the `longitude` coordinate variable name gets converted to + 'projected_x' + + """ + override_variable = varinfo.get_variable(variable_name) + if override_variable is not None: + if override_variable.is_latitude(): + projected_dimension_name = 'projected_y' + elif override_variable.is_longitude(): + projected_dimension_name = 'projected_x' + else: + projected_dimension_name = '' + return projected_dimension_name + + +def get_override_projected_dimensions( + varinfo: VarInfoFromDmr, + variable_name: str, +) -> list[str]: + """ + Returns the projected dimensions names from coordinate variables + """ + latitude_coordinates, longitude_coordinates = get_coordinate_variables( + varinfo, [variable_name] + ) + if latitude_coordinates and longitude_coordinates: + # there should be only 1 lat and lon coordinate for one variable + override_dimensions = [] + override_dimensions.append( + get_override_projected_dimension_name(varinfo, latitude_coordinates[0]) + ) + override_dimensions.append( + get_override_projected_dimension_name(varinfo, longitude_coordinates[0]) + ) + + else: + # if the override is the variable + override_projected_dimension_name = get_override_projected_dimension_name( + varinfo, variable_name + ) + override_dimensions = ['projected_y', 'projected_x'] + if override_projected_dimension_name not in override_dimensions: + override_dimensions = [] + return override_dimensions + + +def get_variables_with_anonymous_dims( + varinfo: VarInfoFromDmr, variables: set[str] +) -> set[str]: + """ + returns a set of variables without any + dimensions + """ + return set( + variable + for variable in variables + if len(varinfo.get_variable(variable).dimensions) == 0 + ) + + +def get_coordinate_variables( + varinfo: VarInfoFromDmr, + requested_variables: Set[str], +) -> tuple[list, list]: + """This method returns coordinate variables that are referenced + in the variables requested. It returns it in a specific order + [latitude, longitude] + """ + + coordinate_variables_set = varinfo.get_references_for_attribute( + requested_variables, 'coordinates' + ) + + latitude_coordinate_variables = [ + coordinate + for coordinate in coordinate_variables_set + if varinfo.get_variable(coordinate).is_latitude() + ] + + longitude_coordinate_variables = [ + coordinate + for coordinate in coordinate_variables_set + if varinfo.get_variable(coordinate).is_longitude() + ] + + return latitude_coordinate_variables, longitude_coordinate_variables + + +def update_dimension_variables( + prefetch_dataset: Dataset, + latitude_coordinate: VariableFromDmr, + longitude_coordinate: VariableFromDmr, + crs: CRS, +) -> Dict[str, ndarray]: + """Generate artificial 1D dimensions variable for each + 2D dimension or coordinate variable + + For each dimension variable: + (1) Check if the dimension variable is 1D. + (2) If it is not 1D and is 2D get the dimension sizes + (3) Get the corner points from the coordinate variables + (4) Get the x-y max-min values + (5) Generate the x-y dimscale array and return to the calling method + + """ + lat_arr, lon_arr = get_lat_lon_arrays( + prefetch_dataset, + latitude_coordinate, + longitude_coordinate, + ) + + lat_fill, lon_fill = get_fill_values_for_coordinates( + latitude_coordinate, longitude_coordinate + ) + + row_size, col_size = get_row_col_sizes_from_coordinate_datasets( + lat_arr, + lon_arr, + ) + geo_grid_points = get_two_valid_geo_grid_points( + lat_arr, lon_arr, lat_fill, lon_fill, row_size, col_size + ) + + x_y_values = get_x_y_values_from_geographic_points(geo_grid_points, crs) + + row_indices, col_indices = zip(*list(x_y_values.keys())) + + x_values, y_values = zip(*list(x_y_values.values())) + + y_dim = get_dimension_scale_from_dimvalues(y_values, row_indices, row_size) + + x_dim = get_dimension_scale_from_dimvalues(x_values, col_indices, col_size) + + return {'projected_y': y_dim, 'projected_x': x_dim} + + +def get_row_col_sizes_from_coordinate_datasets( + lat_arr: ndarray, + lon_arr: ndarray, +) -> Tuple[int, int]: + """ + This method returns the row and column sizes of the coordinate datasets + + """ + row_size = 0 + col_size = 0 + if lat_arr.ndim > 1 and lon_arr.shape == lat_arr.shape: + col_size = lat_arr.shape[0] + row_size = lat_arr.shape[1] + elif lat_arr.ndim == 1 and lon_arr.ndim == 1: + col_size = lat_arr.size + row_size = lon_arr.size + elif lon_arr.shape != lat_arr.shape: + raise IrregularCoordinateVariables(lon_arr.ndim, lat_arr.ndim) + return row_size, col_size + + +def get_lat_lon_arrays( + prefetch_dataset: Dataset, + latitude_coordinate: VariableFromDmr, + longitude_coordinate: VariableFromDmr, +) -> Tuple[ndarray, ndarray]: + """ + This method is used to return the lat lon arrays from a 2D + coordinate dataset. + """ + try: + lat_arr = prefetch_dataset[latitude_coordinate.full_name_path][:] + lon_arr = prefetch_dataset[longitude_coordinate.full_name_path][:] + return lat_arr, lon_arr + except Exception as exception: + raise MissingCoordinateVariable('latitude/longitude') from exception + + +def get_two_valid_geo_grid_points( + lat_arr: ndarray, + lon_arr: ndarray, + lat_fill: float, + lon_fill: float, + row_size: float, + col_size: float, +) -> dict[int, tuple]: + """ + This method is used to return two valid lat lon points from a 2D + coordinate dataset. It gets the row and column of the latitude and longitude + arrays to get two valid points. This does a check for fill values and + This method does not go down to the next row and col. if the selected row and + column all have fills, it will raise an exception in those cases. + """ + first_row_col_index = -1 + first_row_row_index = 0 + next_col_row_index = -1 + next_col_col_index = 1 + lat_row_valid_indices = lon_row_valid_indices = np.empty((0, 0)) + + # get the first row with points that are valid in the lat and lon rows + first_row_row_index, lat_row_valid_indices = get_valid_indices_in_dataset( + lat_arr, row_size, lat_fill, 'latitude', 'row', first_row_row_index + ) + first_row_row_index1, lon_row_valid_indices = get_valid_indices_in_dataset( + lon_arr, row_size, lon_fill, 'longitude', 'row', first_row_row_index + ) + # get a point that is common on both row datasets + if ( + (first_row_row_index == first_row_row_index1) + and (lat_row_valid_indices.size > 0) + and (lon_row_valid_indices.size > 0) + ): + first_row_col_index = np.intersect1d( + lat_row_valid_indices, lon_row_valid_indices + )[0] + + # get a valid column from the latitude and longitude datasets + next_col_col_index, lon_col_valid_indices = get_valid_indices_in_dataset( + lon_arr, col_size, lon_fill, 'longitude', 'col', next_col_col_index + ) + next_col_col_index1, lat_col_valid_indices = get_valid_indices_in_dataset( + lat_arr, col_size, lat_fill, 'latitude', 'col', next_col_col_index + ) + + # get a point that is common to both column datasets + if ( + (next_col_col_index == next_col_col_index1) + and (lat_col_valid_indices.size > 0) + and (lon_col_valid_indices.size > 0) + ): + next_col_row_index = np.intersect1d( + lat_col_valid_indices, lon_col_valid_indices + )[-1] + + # if the whole row and whole column has no valid indices + # we throw an exception now. This can be extended to move + # to the next row/col + if first_row_col_index == -1: + raise InvalidCoordinateVariable('latitude/longitude') + if next_col_row_index == -1: + raise InvalidCoordinateVariable('latitude/longitude') + + geo_grid_indexes = [ + (first_row_row_index, first_row_col_index), + (next_col_row_index, next_col_col_index), + ] + + geo_grid_points = [ + ( + lon_arr[first_row_row_index][first_row_col_index], + lat_arr[first_row_row_index][first_row_col_index], + ), + ( + lon_arr[next_col_row_index][next_col_col_index], + lat_arr[next_col_row_index][next_col_col_index], + ), + ] + + return { + geo_grid_indexes[0]: geo_grid_points[0], + geo_grid_indexes[1]: geo_grid_points[1], + } + + +def get_x_y_values_from_geographic_points(points: Dict, crs: CRS) -> Dict[tuple, tuple]: + """Take an input list of (longitude, latitude) coordinates and project + those points to the target grid. Then return the x-y dimscales + + """ + point_longitudes, point_latitudes = zip(*list(points.values())) + + from_geo_transformer = Transformer.from_crs(4326, crs) + points_x, points_y = ( # pylint: disable=unpacking-non-sequence + from_geo_transformer.transform(point_latitudes, point_longitudes) + ) + + x_y_points = {} + for index, point_x, point_y in zip(list(points.keys()), points_x, points_y): + x_y_points.update({index: (point_x, point_y)}) + + return x_y_points + + +def get_dimension_scale_from_dimvalues( + dim_values: ndarray, dim_indices: ndarray, dim_size: float +) -> ndarray: + """ + return a full dimension scale based on the 2 projected points and + grid size + """ + dim_resolution = 0.0 + if (dim_indices[1] != dim_indices[0]) and (dim_values[1] != dim_values[0]): + dim_resolution = (dim_values[1] - dim_values[0]) / ( + dim_indices[1] - dim_indices[0] + ) + if dim_resolution == 0.0: + raise CannotComputeDimensionResolution(dim_values[0], dim_indices[0]) + + # create the dim scale + dim_asc = dim_values[1] > dim_values[0] + + if dim_asc: + dim_min = dim_values[0] + (dim_resolution * dim_indices[0]) + dim_max = dim_values[0] + (dim_resolution * (dim_size - dim_indices[0] - 1)) + dim_data = np.linspace(dim_min, dim_max, dim_size) + else: + dim_max = dim_values[0] + (-dim_resolution * dim_indices[0]) + dim_min = dim_values[0] - (-dim_resolution * (dim_size - dim_indices[0] - 1)) + dim_data = np.linspace(dim_max, dim_min, dim_size) + + return dim_data + + +def get_valid_indices_in_dataset( + coordinate_arr: ndarray, + dim_size: int, + coordinate_fill: float, + coordinate_name: str, + span_type: str, + start_index: int, +) -> tuple[int, ndarray]: + """ + This method gets valid indices in a row or column of a + coordinate dataset + """ + coordinate_index = start_index + valid_indices = [] + if span_type == 'row': + valid_indices = get_valid_indices( + coordinate_arr[coordinate_index, :], coordinate_fill, coordinate_name + ) + else: + valid_indices = get_valid_indices( + coordinate_arr[:, coordinate_index], coordinate_fill, coordinate_name + ) + while valid_indices.size == 0: + if coordinate_index < dim_size: + coordinate_index = coordinate_index + 1 + if span_type == 'row': + valid_indices = get_valid_indices( + coordinate_arr[coordinate_index, :], + coordinate_fill, + coordinate_name, + ) + else: + valid_indices = get_valid_indices( + coordinate_arr[:, coordinate_index], + coordinate_fill, + coordinate_name, + ) + else: + raise InvalidCoordinateVariable(coordinate_name) + return coordinate_index, valid_indices + + +def get_valid_indices( + coordinate_row_col: ndarray, coordinate_fill: float, coordinate_name: str +) -> ndarray: + """ + Returns indices of a valid array without fill values + """ + + if coordinate_fill: + valid_indices = np.where( + ~np.isclose(coordinate_row_col, float(coordinate_fill)) + )[0] + elif coordinate_name == 'longitude': + valid_indices = np.where( + (coordinate_row_col >= -180.0) & (coordinate_row_col <= 180.0) + )[0] + elif coordinate_name == 'latitude': + valid_indices = np.where( + (coordinate_row_col >= -90.0) & (coordinate_row_col <= 90.0) + )[0] + else: + valid_indices = np.empty((0, 0)) + + return valid_indices + + +def get_fill_values_for_coordinates( + latitude_coordinate: VariableFromDmr, + longitude_coordinate: VariableFromDmr, +) -> tuple[float | None, float | None]: + """ + returns fill values for the variable. If it does not exist + checks for the overrides from the json file. If there is no + overrides, returns None + """ + + lat_fill = None + lon_fill = None + lat_fill_value = latitude_coordinate.get_attribute_value('_FillValue') + lon_fill_value = longitude_coordinate.get_attribute_value('_FillValue') + + if lat_fill_value is not None: + lat_fill = float(lat_fill_value) + if lon_fill_value is not None: + lon_fill = float(lon_fill_value) + + return float(lat_fill), float(lon_fill) diff --git a/hoss/dimension_utilities.py b/hoss/dimension_utilities.py index 9ee8d02..bb8028a 100644 --- a/hoss/dimension_utilities.py +++ b/hoss/dimension_utilities.py @@ -22,8 +22,14 @@ from numpy.ma.core import MaskedArray from varinfo import VariableFromDmr, VarInfoFromDmr -from hoss.bbox_utilities import flatten_list -from hoss.exceptions import InvalidNamedDimension, InvalidRequestedRange +from hoss.coordinate_utilities import ( + get_coordinate_variables, + get_override_projected_dimensions, +) +from hoss.exceptions import ( + InvalidNamedDimension, + InvalidRequestedRange, +) from hoss.utilities import ( format_variable_set_string, get_opendap_nc4, @@ -55,7 +61,7 @@ def is_index_subset(message: Message) -> bool: ) -def prefetch_dimension_variables( +def get_prefetch_variables( opendap_url: str, varinfo: VarInfoFromDmr, required_variables: Set[str], @@ -64,45 +70,39 @@ def prefetch_dimension_variables( access_token: str, config: Config, ) -> str: - """Determine the dimensions that need to be "pre-fetched" from OPeNDAP in + """Determine the variables that need to be "pre-fetched" from OPeNDAP in order to derive index ranges upon them. Initially, this was just spatial and temporal dimensions, but to support generic dimension subsets, all required dimensions must be prefetched, along with any associated bounds variables referred to via the "bounds" metadata - attribute. + attribute. In cases where dimension variables do not exist, coordinate + variables will be prefetched and used to calculate dimension-scale values """ - required_dimensions = varinfo.get_required_dimensions(required_variables) - - # Iterate through all requested dimensions and extract a list of bounds - # references for each that has any. This will produce a list of lists, - # which should be flattened into a single list and then combined into a set - # to remove duplicates. - bounds = set( - flatten_list( - [ - list(varinfo.get_variable(dimension).references.get('bounds')) - for dimension in required_dimensions - if varinfo.get_variable(dimension).references.get('bounds') is not None - ] + prefetch_variables = varinfo.get_required_dimensions(required_variables) + if prefetch_variables: + bounds = varinfo.get_references_for_attribute(prefetch_variables, 'bounds') + prefetch_variables.update(bounds) + else: + latitude_coordinates, longitude_coordinates = get_coordinate_variables( + varinfo, required_variables ) - ) - required_dimensions.update(bounds) + if latitude_coordinates and longitude_coordinates: + prefetch_variables = set(latitude_coordinates + longitude_coordinates) logger.info( 'Variables being retrieved in prefetch request: ' - f'{format_variable_set_string(required_dimensions)}' + f'{format_variable_set_string(prefetch_variables)}' ) - required_dimensions_nc4 = get_opendap_nc4( - opendap_url, required_dimensions, output_dir, logger, access_token, config + prefetch_variables_nc4 = get_opendap_nc4( + opendap_url, prefetch_variables, output_dir, logger, access_token, config ) # Create bounds variables if necessary. - add_bounds_variables(required_dimensions_nc4, required_dimensions, varinfo, logger) - - return required_dimensions_nc4 + add_bounds_variables(prefetch_variables_nc4, prefetch_variables, varinfo, logger) + return prefetch_variables_nc4 def add_bounds_variables( @@ -409,7 +409,9 @@ def get_dimension_indices_from_bounds( def add_index_range( - variable_name: str, varinfo: VarInfoFromDmr, index_ranges: IndexRanges + variable_name: str, + varinfo: VarInfoFromDmr, + index_ranges: IndexRanges, ) -> str: """Append the index ranges of each dimension for the specified variable. If there are no dimensions with listed index ranges, then the full @@ -418,27 +420,42 @@ def add_index_range( the antimeridian or Prime Meridian) will have a minimum index greater than the maximum index. In this case the full dimension range should be requested, as the related values will be masked before returning the - output to the user. + output to the user. When the dimensions are not available, the coordinate + variables are used to calculate the projected dimensions. """ variable = varinfo.get_variable(variable_name) - range_strings = [] + if variable.dimensions: + range_strings = get_range_strings(variable.dimensions, index_ranges) + else: + override_dimensions = get_override_projected_dimensions(varinfo, variable_name) + if override_dimensions: + range_strings = get_range_strings(override_dimensions, index_ranges) + + if all(range_string == '[]' for range_string in range_strings): + indices_string = '' + else: + indices_string = ''.join(range_strings) + return f'{variable_name}{indices_string}' - for dimension in variable.dimensions: - dimension_range = index_ranges.get(dimension) +def get_range_strings( + variable_dimensions: list, + index_ranges: IndexRanges, +) -> list: + """Calculates the index ranges for each dimension of the variable + and returns the list of index ranges + """ + range_strings = [] + for dimension in variable_dimensions: + dimension_range = index_ranges.get(dimension) if dimension_range is not None and dimension_range[0] <= dimension_range[1]: range_strings.append(f'[{dimension_range[0]}:{dimension_range[1]}]') else: range_strings.append('[]') - if all(range_string == '[]' for range_string in range_strings): - indices_string = '' - else: - indices_string = ''.join(range_strings) - - return f'{variable_name}{indices_string}' + return range_strings def get_fill_slice(dimension: str, fill_ranges: IndexRanges) -> slice: @@ -549,7 +566,12 @@ def get_dimension_bounds( be returned. """ - bounds = varinfo.get_variable(dimension_name).references.get('bounds') + try: + # For pseudo-variables, `varinfo.get_variable` returns `None` and + # therefore has no `references` attribute. + bounds = varinfo.get_variable(dimension_name).references.get('bounds') + except AttributeError: + bounds = None if bounds is not None: try: diff --git a/hoss/exceptions.py b/hoss/exceptions.py index 1cb1439..574f27f 100644 --- a/hoss/exceptions.py +++ b/hoss/exceptions.py @@ -57,7 +57,7 @@ class InvalidRequestedRange(CustomError): def __init__(self): super().__init__( 'InvalidRequestedRange', - 'Input request specified range outside supported ' 'dimension range', + 'Input request specified range outside supported dimension range', ) @@ -108,6 +108,65 @@ def __init__(self): ) +class MissingCoordinateVariable(CustomError): + """This exception is raised when HOSS tries to get latitude and longitude + variables and they are missing or empty. These variables are referred to + in the science variables with coordinate attributes. + + """ + + def __init__(self, referring_variable): + super().__init__( + 'MissingCoordinateVariable', + f'Coordinate: "{referring_variable}" is ' + 'not present in source granule file.', + ) + + +class InvalidCoordinateVariable(CustomError): + """This exception is raised when HOSS tries to get latitude and longitude + variables and they have fill values to the extent that it cannot be used. + These variables are referred in the science variables with coordinate attributes. + + """ + + def __init__(self, referring_variable): + super().__init__( + 'InvalidCoordinateVariable', + f'Coordinate: "{referring_variable}" is ' + 'not valid in source granule file.', + ) + + +class IrregularCoordinateVariables(CustomError): + """This exception is raised when HOSS tries to get latitude and longitude + coordinate variable and they are missing or empty. These variables are referred to + in the science variables with coordinate attributes. + + """ + + def __init__(self, longitude_shape, latitude_shape): + super().__init__( + 'IrregularCoordinateVariables', + f'Longitude coordinate shape: "{longitude_shape}"' + f'does not match the latitude coordinate shape: "{latitude_shape}"', + ) + + +class CannotComputeDimensionResolution(CustomError): + """This exception is raised when the two values passed to + the method computing the resolution are equal + + """ + + def __init__(self, dim_value, dim_index): + super().__init__( + 'CannotComputeDimensionResolution', + 'Cannot compute the dimension resolution for ' + f'dim_value: "{dim_value}" dim_index: "{dim_index}"', + ) + + class UnsupportedShapeFileFormat(CustomError): """This exception is raised when the shape file included in the input Harmony message is not GeoJSON. diff --git a/hoss/hoss_config.json b/hoss/hoss_config.json index c214d6b..9c75f80 100644 --- a/hoss/hoss_config.json +++ b/hoss/hoss_config.json @@ -59,24 +59,6 @@ "Epoch": "2018-01-01T00:00:00.000000" } ], - "Grid_Mapping_Data": [ - { - "Grid_Mapping_Dataset_Name": "EASE2_Global", - "grid_mapping_name": "lambert_cylindrical_equal_area", - "standard_parallel": 30.0, - "longitude_of_central_meridian": 0.0, - "false_easting": 0.0, - "false_northing": 0.0 - }, - { - "Grid_Mapping_Dataset_Name": "EASE2_Polar", - "grid_mapping_name": "lambert_azimuthal_equal_area", - "longitude_of_projection_origin": 0.0, - "latitude_of_projection_origin": 90.0, - "false_easting": 0.0, - "false_northing": 0.0 - } - ], "CF_Overrides": [ { "Applicability": { @@ -161,34 +143,58 @@ { "Applicability": { "Mission": "SMAP", - "ShortNamePath": "SPL3FT(P|P_E)" + "ShortNamePath": "SPL3FT(P|P_E)", + "Variable_Pattern": "(?i).*global.*" }, - "Applicability_Group": [ + "Attributes": [ { - "Applicability": { - "Variable_Pattern": "(?i).*global.*" - }, - "Attributes": [ - { - "Name": "Grid_Mapping", - "Value": "EASE2_Global" - } - ], - "_Description": "Some versions of these collections omit global grid mapping information" - }, + "Name": "grid_mapping", + "Value": "/EASE2_global_projection" + } + ], + "_Description": "SMAP L3 collections omit global grid mapping information" + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3FT(P|P_E)", + "Variable_Pattern": "(?i).*polar.*" + }, + "Attributes": [ { - "Applicability": { - "Variable_Pattern": "(?i).*polar.*" - }, - "Attributes": [ - { - "Name": "Grid_Mapping", - "Value": "EASE2_Polar" - } - ], - "_Description": "Some versions of these collections omit polar grid mapping information" + "Name": "grid_mapping", + "Value": "/EASE2_polar_projection" } - ] + ], + "_Description": "SMAP L3 collections omit polar grid mapping information" + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3SMP_E", + "Variable_Pattern": "Soil_Moisture_Retrieval_Data_(A|P)M/.*" + }, + "Attributes": [ + { + "Name": "grid_mapping", + "Value": "/EASE2_global_projection" + } + ], + "_Description": "SMAP L3 collections omit global grid mapping information" + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3SMP_E", + "Variable_Pattern": "Soil_Moisture_Retrieval_Data_Polar_(A|P)M/.*" + }, + "Attributes": [ + { + "Name": "grid_mapping", + "Value": "/EASE2_polar_projection" + } + ], + "_Description": "SMAP L3 collections omit polar grid mapping information" }, { "Applicability": { @@ -197,11 +203,83 @@ }, "Attributes": [ { - "Name": "Grid_Mapping", - "Value": "EASE2_Polar" + "Name": "grid_mapping", + "Value": "/EASE2_polar_projection" } ], - "_Description": "Some versions of these collections omit polar grid mapping information" + "_Description": "SMAP L3 collections omit polar grid mapping information" + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3SM(P|A|AP)|SPL2SMAP_S" + }, + "Attributes": [ + { + "Name": "grid_mapping", + "Value": "/EASE2_global_projection" + } + ], + "_Description": "SMAP L3 collections omit global grid mapping information" + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3FT(P|P_E)|SPL3SM(P|P_E|A|AP)|SPL2SMAP_S", + "Variable_Pattern": "/EASE2_global_projection" + }, + "Attributes": [ + { + "Name": "grid_mapping_name", + "Value": "lambert_cylindrical_equal_area" + }, + { + "Name":"standard_parallel", + "Value": 30.0 + }, + { + "Name": "longitude_of_central_meridian", + "Value": 0.0 + }, + { + "Name": "false_easting", + "Value": 0.0 + }, + { + "Name": "false_northing", + "Value": 0.0 + } + ], + "_Description": "Provide missing global grid mapping attributes for SMAP L3 collections." + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3FT(P|P_E)|SPL3SM(P|P_E|A|AP)|SPL2SMAP_S", + "Variable_Pattern": "/EASE2_polar_projection" + }, + "Attributes": [ + { + "Name": "grid_mapping_name", + "Value": "lambert_azimuthal_equal_area" + }, + { "Name": "longitude_of_projection_origin", + "Value" : 0.0 + }, + { + "Name": "latitude_of_projection_origin", + "Value": 90.0 + }, + { + "Name": "false_easting", + "Value": 0.0 + }, + { + "Name": "false_northing", + "Value": 0.0 + } + ], + "_Description": "Provide missing polar grid mapping attributes for SMAP L3 collections." }, { "Applicability": { @@ -211,8 +289,22 @@ }, "Attributes": [ { - "Name": "_fill", - "Value": "-9999" + "Name": "_FillValue", + "Value": "-9999.0" + } + ], + "_Description": "Ensure metadata fill value matches what is present in arrays." + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3SM(A|P|AP|P_E)", + "Variable_Pattern": "/Soil_Moisture_Retrieval_(Data|Data_AM|Data_Polar_AM)/(latitude|longitude).*" + }, + "Attributes": [ + { + "Name": "_FillValue", + "Value": "-9999.0" } ], "_Description": "Ensure metadata fill value matches what is present in arrays." diff --git a/hoss/projection_utilities.py b/hoss/projection_utilities.py index bdacdc0..d84c64d 100644 --- a/hoss/projection_utilities.py +++ b/hoss/projection_utilities.py @@ -57,9 +57,21 @@ def get_variable_crs(variable: str, varinfo: VarInfoFromDmr) -> CRS: if grid_mapping is not None: try: - crs = CRS.from_cf(varinfo.get_variable(grid_mapping).attributes) + grid_mapping_variable = varinfo.get_variable(grid_mapping) + if grid_mapping_variable is not None: + cf_attributes = grid_mapping_variable.attributes + else: + # check for any overrides + cf_attributes = varinfo.get_missing_variable_attributes(grid_mapping) + + if cf_attributes: + crs = CRS.from_cf(cf_attributes) + else: + raise MissingGridMappingVariable(grid_mapping, variable) + except AttributeError as exception: raise MissingGridMappingVariable(grid_mapping, variable) from exception + else: raise MissingGridMappingMetadata(variable) diff --git a/hoss/spatial.py b/hoss/spatial.py index 79eb5c2..60eda03 100644 --- a/hoss/spatial.py +++ b/hoss/spatial.py @@ -27,7 +27,7 @@ from harmony.message import Message from netCDF4 import Dataset from numpy.ma.core import MaskedArray -from varinfo import VarInfoFromDmr +from varinfo import VariableFromDmr, VarInfoFromDmr from hoss.bbox_utilities import ( BBox, @@ -35,6 +35,11 @@ get_harmony_message_bbox, get_shape_file_geojson, ) +from hoss.coordinate_utilities import ( + get_coordinate_variables, + get_variables_with_anonymous_dims, + update_dimension_variables, +) from hoss.dimension_utilities import ( IndexRange, IndexRanges, @@ -78,6 +83,10 @@ def get_spatial_index_ranges( around the exterior of the user-defined GeoJSON shape, to ensure the correct extents are derived. + if geographic and projected dimensions are not specified in the granule, + the coordinate datasets are used to calculate the x-y dimensions and the index ranges + are calculated similar to a projected grid. + """ bounding_box = get_harmony_message_bbox(harmony_message) index_ranges = {} @@ -91,7 +100,7 @@ def get_spatial_index_ranges( ) with Dataset(dimensions_path, 'r') as dimensions_file: - if len(geographic_dimensions) > 0: + if geographic_dimensions: # If there is no bounding box, but there is a shape file, calculate # a bounding box to encapsulate the GeoJSON shape: if bounding_box is None and shape_file_path is not None: @@ -103,7 +112,7 @@ def get_spatial_index_ranges( dimension, varinfo, dimensions_file, bounding_box ) - if len(projected_dimensions) > 0: + if projected_dimensions: for non_spatial_variable in non_spatial_variables: index_ranges.update( get_projected_x_y_index_ranges( @@ -115,6 +124,26 @@ def get_spatial_index_ranges( shape_file_path=shape_file_path, ) ) + variables_with_anonymous_dims = get_variables_with_anonymous_dims( + varinfo, required_variables + ) + for variable_with_anonymous_dims in variables_with_anonymous_dims: + latitude_coordinates, longitude_coordinates = get_coordinate_variables( + varinfo, [variable_with_anonymous_dims] + ) + if latitude_coordinates and longitude_coordinates: + index_ranges.update( + get_x_y_index_ranges_from_coordinates( + variable_with_anonymous_dims, + varinfo, + dimensions_file, + varinfo.get_variable(latitude_coordinates[0]), + varinfo.get_variable(longitude_coordinates[0]), + index_ranges, + bounding_box=bounding_box, + shape_file_path=shape_file_path, + ) + ) return index_ranges @@ -187,6 +216,73 @@ def get_projected_x_y_index_ranges( return x_y_index_ranges +def get_x_y_index_ranges_from_coordinates( + non_spatial_variable: str, + varinfo: VarInfoFromDmr, + prefetch_coordinate_datasets: Dataset, + latitude_coordinate: VariableFromDmr, + longitude_coordinate: VariableFromDmr, + index_ranges: IndexRanges, + bounding_box: BBox = None, + shape_file_path: str = None, +) -> IndexRanges: + """This function returns a dictionary containing the minimum and maximum + index ranges for the projected_x and projected_y recalculated dimension scales + + index_ranges = {'projected_x': (20, 42), 'projected_y': (31, 53)} + + This method is called when the CF standards are not followed + in the source granule and only coordinate datasets are provided. + The coordinate datasets along with the crs is used to calculate + the x-y projected dimension scales. The dimensions of the input, + non-spatial variable are checked for associated coordinates. If + these are present, and they have not already been added to the + `index_ranges` cache, the extents of the input spatial subset + are determined in these projected coordinates. The minimum and + maximum values are then derived from these projected coordinate + points. + + """ + + crs = get_variable_crs(non_spatial_variable, varinfo) + projected_x = 'projected_x' + projected_y = 'projected_y' + override_dimension_variables = update_dimension_variables( + prefetch_coordinate_datasets, + latitude_coordinate, + longitude_coordinate, + crs, + ) + + if not set((projected_x, projected_y)).issubset(set(index_ranges.keys())): + + x_y_extents = get_projected_x_y_extents( + override_dimension_variables[projected_x][:], + override_dimension_variables[projected_y][:], + crs, + shape_file=shape_file_path, + bounding_box=bounding_box, + ) + + x_index_ranges = get_dimension_index_range( + override_dimension_variables[projected_x][:], + x_y_extents['x_min'], + x_y_extents['x_max'], + bounds_values=None, + ) + y_index_ranges = get_dimension_index_range( + override_dimension_variables[projected_y][:], + x_y_extents['y_min'], + x_y_extents['y_max'], + bounds_values=None, + ) + x_y_index_ranges = {projected_x: x_index_ranges, projected_y: y_index_ranges} + else: + x_y_index_ranges = {} + + return x_y_index_ranges + + def get_geographic_index_range( dimension: str, varinfo: VarInfoFromDmr, diff --git a/hoss/subset.py b/hoss/subset.py index 8a01321..a08e590 100644 --- a/hoss/subset.py +++ b/hoss/subset.py @@ -21,13 +21,17 @@ IndexRanges, add_index_range, get_fill_slice, + get_prefetch_variables, get_requested_index_ranges, is_index_subset, - prefetch_dimension_variables, ) from hoss.spatial import get_spatial_index_ranges from hoss.temporal import get_temporal_index_ranges -from hoss.utilities import download_url, format_variable_set_string, get_opendap_nc4 +from hoss.utilities import ( + download_url, + format_variable_set_string, + get_opendap_nc4, +) def subset_granule( @@ -87,7 +91,7 @@ def subset_granule( if request_is_index_subset: # Prefetch all dimension variables in full: - dimensions_path = prefetch_dimension_variables( + dimensions_path = get_prefetch_variables( opendap_url, varinfo, required_variables, @@ -122,6 +126,7 @@ def subset_granule( shape_file_path = get_request_shape_file( harmony_message, output_dir, logger, config ) + index_ranges.update( get_spatial_index_ranges( required_variables, diff --git a/pip_requirements.txt b/pip_requirements.txt index 41ba9c5..1bb9bce 100644 --- a/pip_requirements.txt +++ b/pip_requirements.txt @@ -1,6 +1,6 @@ # This file should contain requirements to be installed via Pip. # Open source packages available from PyPI -earthdata-varinfo ~= 1.0.0 +earthdata-varinfo ~= 2.3.0 harmony-service-lib ~= 1.0.25 netCDF4 ~= 1.6.4 numpy ~= 1.24.2 diff --git a/tests/data/SC_SPL3SMP_008.dmr b/tests/data/SC_SPL3SMP_008.dmr new file mode 100644 index 0000000..b45abae --- /dev/null +++ b/tests/data/SC_SPL3SMP_008.dmr @@ -0,0 +1,2778 @@ + + + + 3.21.0-428 + + + 3.21.0-428 + + + libdap-3.21.0-103 + + + +# TheBESKeys::get_as_config() +AllowedHosts=^https?:\/\/ +BES.Catalog.catalog.FollowSymLinks=Yes +BES.Catalog.catalog.RootDirectory=/usr/share/hyrax +BES.Catalog.catalog.TypeMatch=dmrpp:.*\.(dmrpp)$; +BES.Catalog.catalog.TypeMatch+=h5:.*(\.bz2|\.gz|\.Z)?$; +BES.Data.RootDirectory=/dev/null +BES.LogName=./bes.log +BES.UncompressCache.dir=/tmp/hyrax_ux +BES.UncompressCache.prefix=ux_ +BES.UncompressCache.size=500 +BES.module.cmd=/usr/lib64/bes/libdap_xml_module.so +BES.module.dap=/usr/lib64/bes/libdap_module.so +BES.module.dmrpp=/usr/lib64/bes/libdmrpp_module.so +BES.module.h5=/usr/lib64/bes/libhdf5_module.so +BES.modules=dap,cmd,h5,dmrpp +H5.DefaultHandleDimensions=true +H5.EnableCF=false +H5.EnableCheckNameClashing=true + + + + build_dmrpp -c /tmp/bes_conf_IAud -f /usr/share/hyrax/DATA/SMAP_L3_SM_P_20150331_R18290_002.h5 -r /tmp/dmr__0PmwFd -u OPeNDAP_DMRpp_DATA_ACCESS_URL -M + + + + + + + The SMAP observatory houses an L-band radiometer that operates at 1.414 GHz and an L-band radar that operates at 1.225 GHz. The instruments share a rotating reflector antenna with a 6 meter aperture that scans over a 1000 km swath. The bus is a 3 axis stabilized spacecraft that provides momentum compensation for the rotating antenna. + + + 14.60000038 + + + SMAP + + + + + JPL CL#14-2285, JPL 400-1567 + + + SMAP Handbook + + + 2014-07-01 + + + + + JPL CL#14-2285, JPL 400-1567 + + + SMAP Handbook + + + 2014-07-01 + + + + + The SMAP 1.414 GHz L-Band Radiometer + + + L-Band Radiometer + + + SMAP RAD + + + + + The SMAP 1.225 GHz L-Band Radar Instrument + + + L-Band Synthetic Aperture Radar + + + SMAP SAR + + + + + JPL CL#14-2285, JPL 400-1567 + + + SMAP Handbook + + + 2014-07-01 + + + + + + soil_moisture + + + + Percentage of EASE2 grid cells with Retrieved Soil Moistures outside the Acceptable Range. + + + Percentage of EASE2 grid cells with soil moisture measures that fall outside of a predefined acceptable range. + + + directInternal + + + percent + + + 100. + + + + + Percentage of EASE2 grid cells that lack soil moisture retrieval values relative to the total number of grid cells where soil moisture retrieval was attempted. + + + Percent of Missing Data + + + percent + + + 176.5011139 + + + directInternal + + + + + + eng + + + utf8 + + + 1.0 + + + Product Specification Document for the SMAP Level 3 Passive Soil Moisture Product (L3_SM_P) + + + 2013-02-08 + + + L3_SM_P + + + + + doi:10.5067/OMHVSRGFX38O + + + SPL3SMP + + + SMAP + + + utf8 + + + National Aeronautics and Space Administration (NASA) + + + eng + + + 008 + + + Daily global composite of up-to 30 half-orbit L2_SM_P soil moisture estimates based on radiometer brightness temperature measurements acquired by the SMAP radiometer during ascending and descending half-orbits at approximately 6 PM and 6 AM local solar time. + + + onGoing + + + 2021-08-31 + + + The software that generates the Level 3 Soil Moisture Passive product and the data system that automates its production were designed and implemented + at the Jet Propulsion Laboratory, California Institute of Technology in Pasadena, California. + + + geoscientificInformation + + + The SMAP L3_SM_P algorithm provides daily global composite of soil moistures based on radiometer data on a 36 km grid. + + + SMAP L3 Radiometer Global Daily 36 km EASE-Grid Soil Moisture + + + National Snow and Ice Data Center + + + R18 + + + grid + + + The Calibration and Validation Version 2 Release of the SMAP Level 3 Daily Global Composite Passive Soil Moisture Science Processing Software. + + + + + SPL3SMP + + + utf8 + + + be9694f7-6503-4c42-8423-4c824df6c1f2 + + + eng + + + 1.8.13 + + + 008 + + + Daily global composite of up-to 15 half-orbit L2_SM_P soil moisture estimates based on radiometer brightness temperature measurements acquired by the SMAP radiometer during descending half-orbits at approximately 6 AM local solar time. + + + 2022-03-11 + + + onGoing + + + The software that generates the Level 3 SM_P product and the data system that automates its production were designed and implemented at the Jet Propulsion Laboratory, California Institute of Technology in Pasadena, California. + + + geoscientificInformation + + + The SMAP L3_SM_P effort provides soil moistures based on radiometer data on a 36 km grid. + + + HDF5 + + + SMAP_L3_SM_P_20150331_R18290_002.h5 + + + asNeeded + + + R18290 + + + Jet Propulsion Laboratory + + + 2016-05-01 + + + L3_SM_P + + + grid + + + The Calibration and Validation Version 2 Release of the SMAP Level 3 Daily Global Composite Passive Soil Moisture Science Processing Software. + + + + + Soil moisture is retrieved over land targets on the descending (AM) SMAP half-orbits when the SMAP spacecraft is travelling from North to South, while the SMAP instruments are operating in the nominal mode. The L3_SM_P product represents soil moisture retrieved over the entre UTC day. Retrievals are performed but flagged as questionable over urban areas, mountainous areas with high elevation variability, and areas with high ( &gt; 5 kg/m**2) vegetation water content; for retrievals using the high-resolution radar, cells in the nadir region are also flagged. Retrievals are inhibited for permanent snow/ice, frozen ground, and excessive static or transient open water in the cell, and for excessive RFI in the sensor data. + + + 180. + + + -180. + + + -85.04450226 + + + 85.04450226 + + + 2015-03-31T00:00:00.000Z + + + 2015-03-31T23:59:59.999Z + + + + + SMAP_L3_SM_P_20150331_R18290_002.qa + + + An ASCII product that contains statistical information on data product results. These statistics enable data producers and users to assess the quality of the data in the data product granule. + + + 2022-03-11 + + + + + 0 + + + 0 + + + 0 + + + 2 + + + SMAP Fixed Earth Grids, SMAP Science Document no: 033, May 11, 2009 + + + point + + + + 406 + + + 36. + + + + + EASE-Grid 2.0 + + + EASE-Grid 2.0: Incremental but Significant Improvements for Earth-Gridded Data Sets (ISPRS Int. J. Geo-Inf. 2012, 1, 32-45; doi:10.3390/ijgi1010032) + + + 2012-03-31 + + + + + 964 + + + 36. + + + + + The Equal-Area Scalable Earth Grid (EASE-Grid 2.0) is used for gridding satellite data sets. The EASE-Grid 2.0 is defined on the WGS84 ellipsoid to allow users to import data into standard GIS software formats such as GeoTIFF without reprojection. + + + Equal-Area Scalable Earth Grid + + + + + + 869 + + + 864 + + + + + + A configuration file that specifies the complete set of elements within the input Level 2 SM_P Product that the Radiometer Level 3_SM_P Science Processing Software (SPS) needs in order to function. + + + R18290 + + + SMAP_L3_SM_P_SPS_InputConfig_L2_SM_P.xml + + + 2022-03-11 + + + + + Precomputed longitude at each EASEGrid cell on 36-km grid on Global Cylindrical Projection + + + 002 + + + EZ2Lon_M36_002.float32 + + + 2013-05-09 + + + + + Passive soil moisture estimates onto a 36-km global Earth-fixed grid, based on radiometer measurements acquired when the SMAP spacecraft is travelling from North to South at approximately 6:00 AM local time. + + + SMAP_L2_SM_P_00864_D_20150331T162851_R18290_001.h5 + SMAP_L2_SM_P_00865_A_20150331T162945_R18290_001.h5 + SMAP_L2_SM_P_00865_D_20150331T171859_R18290_001.h5 + SMAP_L2_SM_P_00866_A_20150331T180814_R18290_001.h5 + SMAP_L2_SM_P_00866_D_20150331T185725_R18290_001.h5 + SMAP_L2_SM_P_00867_A_20150331T194640_R18290_001.h5 + SMAP_L2_SM_P_00867_D_20150331T203555_R18290_001.h5 + SMAP_L2_SM_P_00868_A_20150331T212510_R18290_001.h5 + SMAP_L2_SM_P_00868_D_20150331T221420_R18290_001.h5 + SMAP_L2_SM_P_00869_A_20150331T230335_R18290_001.h5 + SMAP_L2_SM_P_00869_D_20150331T235250_R18290_001.h5 + + + doi:10.5067/LPJ8F0TAK6E0 + + + L2_SM_P + + + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + 2022-02-22 + + + 36. + + + + + A configuration file that specifies the source of the values for each of the data elements that comprise the metadata in the output Radiometer Level 3_SM_P product. + + + R18290 + + + SMAP_L3_SM_P_SPS_MetConfig_L2_SM_P.xml + + + 2022-03-11 + + + + + A configuration file that lists the entire content of the output Radiometer Level 3_SM_P_ product. + + + R18290 + + + SMAP_L3_SM_P_SPS_OutputConfig_L3_SM_P.xml + + + 2022-03-11 + + + + + A configuration file generated automatically within the SMAP data system that specifies all of the conditions required for each individual run of the Radiometer Level 3 SM P Science Processing Software (SPS). + + + R18290 + + + SMAP_L3_SM_P_SPS_RunConfig_20220311T185327319.xml + + + 2022-03-11 + + + + + + Soil moisture retrieved using default retrieval algorithm from brightness temperatures acquired by the SMAP radiometer during the spacecraft descending pass. Level 2 granule data are then mosaicked on a daily basis to form the Level 3 product. + + + 2022-03-11T18:53:27.319Z + + + Algorithm Theoretical Basis Document: SMAP L2 and L3 Radiometer Soil Moisture (Passive) Data Products: L2_SM_P &amp; L3_SM_P + + + 2000-01-01T11:58:55.816Z + + + 023 + + + L3_SM_P_SPS + + + 2021-08-17 + + + 015 + + + L3_SM_P_SPS + + + Version 1.1 + + + 2019-04-15 + + + 2015-10-30 + + + 026 + + + Level 3 soil moisture product is formed by mosaicking Level 2 soil moisture granule data acquired over one day. + + + Algorithm Theoretical Basis Document: SMAP L2 and L3 Radiometer Soil Moisture (Passive) Data Products: L2_SM_P &amp; L3_SM_P + + + 2451545. + + + J2000 + + + 2012-10-26 + + + Soil Moisture Active Passive Mission (SMAP) Science Data System (SDS) Operations Facility + + + Soil Moisture Active Passive (SMAP) Radiometer processing algorithm + + + Preliminary + + + + + + + + + Longitude of the center of the Earth based grid cell. + + + degrees_east + + + + + + + Latitude of the center of the Earth based grid cell. + + + degrees_north + + + + + + + 0. + + + The fraction of the area of the 36 km grid cell that is covered by static water based on a Digital Elevation Map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + + + Representative SCA-V soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + + + Representative angle between the antenna boresight vector and the normal to the Earth&apos;s surface for all footprints within the cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 90. + + + -9999. + + + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in UTC. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + + + The measured opacity of the vegetation used in the DCA retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + + + Bit flags that represent the quality of the horizontal polarization brightness temperature within each grid cell + + + 65534 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Horizontal_polarization_quality Horizontal_polarization_range Horizontal_polarization_RFI_detection Horizontal_polarization_RFI_correction Horizontal_polarization_NEDT Horizontal_polarization_direct_sun_correction Horizontal_polarization_reflected_sun_correction Horizontal_polarization_reflected_moon_correction Horizontal_polarization_direct_galaxy_correction Horizontal_polarization_reflected_galaxy_correction Horizontal_polarization_atmosphere_correction Horizontal_polarization_Faraday_rotation_correction Horizontal_polarization_null_value_bit Horizontal_polarization_water_correction Horizontal_polarization_RFI_check Horizontal_polarization_RFI_clean + + + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + + 254 + + + An enumerated type that specifies the most common landcover class in the grid cell based on the IGBP landcover map. The array order is longitude (ascending), followed by latitude (descending), and followed by IGBP land cover type descending dominance (only the first three types are listed) + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + + + The row index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 405 + + + 65534 + + + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Vertical polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Fourth stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Weighted average of the longitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + -180. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 179.9989929 + + + -9999. + + + + + + + + + The measured opacity of the vegetation used in the SCA-H retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the SCA-H retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/roughness_coefficient + + + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-H within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + + 0. + + + The fraction of the grid cell that contains the most common land cover in that area based on the IGBP landcover map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + + + 0. + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-V within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + /Soil_Moisture_Retrieval_Data_AM/retrieval_qual_flag_dca + + + + + + + + + Representative measure of water in the vegetation within the 36 km grid cell. + + + kg/m**2 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 20. + + + -9999. + + + + + + + + + Vertical polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-V within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Representative SCA-H soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + + + Gain weighted fraction of static water within the radiometer horizontal polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-H within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + + + Third stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + 65534 + + + Bit flags that represent the quality of the 3rd Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 3rd_Stokes_quality 3rd_Stokes_range 3rd_Stokes_RFI_detection 3rd_Stokes_RFI_correction 3rd_Stokes_NEDT 3rd_Stokes_direct_sun_correction 3rd_Stokes_reflected_sun_correction 3rd_Stokes_reflected_moon_correction 3rd_Stokes_direct_galaxy_correction 3rd_Stokes_reflected_galaxy_correction 3rd_Stokes_atmosphere_correction 3rd_Stokes_null_value_bit 3rd_Stokes_RFI_check 3rd_Stokes_RFI_clean + + + + + + + + + 65534 + + + Bit flags that represent the quality of the 4th Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 4th_Stokes_quality 4th_Stokes_range 4th_Stokes_RFI_detection 4th_Stokes_RFI_correction 4th_Stokes_NEDT 4th_Stokes_direct_sun_correction 4th_Stokes_reflected_sun_correction 4th_Stokes_reflected_moon_correction 4th_Stokes_direct_galaxy_correction 4th_Stokes_reflected_galaxy_correction 4th_Stokes_atmosphere_correction 4th_Stokes_null_value_bit 4th_Stokes_RFI_check 4th_Stokes_RFI_clean + + + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + 0. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 330. + + + -9999. + + + + + + + + + Gain weighted fraction of static water within the radiometer vertical polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Indicates if the grid point lies on land (0) or water (1). + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 1 + + + 65534 + + + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in seconds since noon on January 1, 2000 UTC. + + + seconds + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.90000000002 + + + 940000000. + + + -9999. + + + + + + + + + The measured opacity of the vegetation used in the DCA retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/vegetation_opacity + + + + + + + + + A unitless value that is indicative of aggregated bulk_density within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 2.650000095 + + + -9999. + + + + + + + + + Net uncertainty measure of soil moisture measure for the Earth based grid cell. - Calculation method is TBD. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 0.200000003 + + + -9999. + + + + + + + + + The fraction of the area of the 36 km grid cell that is covered by water based on the radar detection algorithm. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + 65534 + + + Bit flags that represent the quality of the vertical polarization brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Vertical_polarization_quality Vertical_polarization_range Vertical_polarization_RFI_detection Vertical_polarization_RFI_correction Vertical_polarization_NEDT Vertical_polarization_direct_sun_correction Vertical_polarization_reflected_sun_correction Vertical_polarization_reflected_moon_correction Vertical_polarization_direct_galaxy_correction Vertical_polarization_reflected_galaxy_correction Vertical_polarization_atmosphere_correction Vertical_polarization_Faraday_rotation_correction Vertical_polarization_null_value_bit Vertical_polarization_water_correction Vertical_polarization_RFI_check Vertical_polarization_RFI_clean + + + + + + + + + Weighted average of the latitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -90. + + + 90. + + + -9999. + + + + + + + + + The column index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 963 + + + 65534 + + + + + + + + + Temperature at land surface based on GMAO GEOS-5 data. + + + Kelvins + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 350. + + + -9999. + + + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/soil_moisture + + + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the SCA-V retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + + + Fraction of the 36 km grid cell that is denoted as frozen. Based on binary flag that specifies freeze thaw conditions in each of the component 3 km grid cells. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Bit flags that record ambient surface conditions for the grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s + + + 36_km_static_water_body 36_km_radar_water_body_detection 36_km_coastal_proximity 36_km_urban_area 36_km_precipitation 36_km_snow_or_ice 36_km_permanent_snow_or_ice 36_km_radiometer_frozen_ground 36_km_model_frozen_ground 36_km_mountainous_terrain 36_km_dense_vegetation 36_km_nadir_region + + + + + + + + + The measured opacity of the vegetation used in the SCA-V retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/albedo + + + + + + + + + A unitless value that is indicative of aggregated clay fraction within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + + + A unitless value that is indicative of aggregated bulk density within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 2.650000095 + + + -9999. + + + + + + + Representative angle between the antenna boresight vector and the normal to the Earth&apos;s surface for all footprints within the cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 90. + + + -9999. + + + + + + + The row index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 405 + + + 65534 + + + + + + + The fraction of the area of the 36 km grid cell that is covered by static water based on a Digital Elevation Map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Fraction of the 36 km grid cell that is denoted as frozen. Based on binary flag that specifies freeze thaw conditions in each of the component 3 km grid cells. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/roughness_coefficient_dca_pm + + + + + + + Bit flags that record ambient surface conditions for the grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s + + + 36_km_static_water_body 36_km_radar_water_body_detection 36_km_coastal_proximity 36_km_urban_area 36_km_precipitation 36_km_snow_or_ice 36_km_permanent_snow_or_ice 36_km_radar_frozen_ground 36_km_model_frozen_ground 36_km_mountainous_terrain 36_km_dense_vegetation 36_km_nadir_region + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the SCA-V retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-V retrievals within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + 0. + + + Gain weighted fraction of static water within the radiometer vertical polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-V retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + 65534 + + + Bit flags that represent the quality of the 4th Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 4th_Stokes_quality 4th_Stokes_range 4th_Stokes_RFI_detection 4th_Stokes_RFI_correction 4th_Stokes_NEDT 4th_Stokes_direct_sun_correction 4th_Stokes_reflected_sun_correction 4th_Stokes_reflected_moon_correction 4th_Stokes_direct_galaxy_correction 4th_Stokes_reflected_galaxy_correction 4th_Stokes_atmosphere_correction 4th_Stokes_null_value_bit 4th_Stokes_RFI_check 4th_Stokes_RFI_clean + + + + + + + Third stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + /Soil_Moisture_Retrieval_Data_PM/retrieval_qual_flag_pm + + + + + + + Representative SCA-V soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the SCA-H retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + The measured opacity of the vegetation used in SCA-H retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + Kelvin + + + 0. + + + Vertical polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 330. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-H retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Bit flags that represent the quality of the horizontal polarization brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Horizontal_polarization_quality Horizontal_polarization_range Horizontal_polarization_RFI_detection Horizontal_polarization_RFI_correction Horizontal_polarization_NEDT Horizontal_polarization_direct_sun_correction Horizontal_polarization_reflected_sun_correction Horizontal_polarization_reflected_moon_correction Horizontal_polarization_direct_galaxy_correction Horizontal_polarization_reflected_galaxy_correction Horizontal_polarization_atmosphere_correction Horizontal_polarization_Faraday_rotation_correction Horizontal_polarization_null_value_bit Horizontal_polarization_water_correction Horizontal_polarization_RFI_check Horizontal_polarization_RFI_clean + + + + + + + A unitless value that is indicative of aggregated clay fraction within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Weighted average of the latitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -90. + + + 90. + + + -9999. + + + + + + + The column index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 963 + + + 65534 + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in seconds since noon on January 1, 2000 UTC. + + + seconds + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.90000000002 + + + 940000000. + + + -9999. + + + + + + + Fourth stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + Net uncertainty measure of soil moisture measure for the Earth based grid cell. - Calculation method is TBD. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 0.200000003 + + + -9999. + + + + + + + + 254 + + + An enumerated type that specifies the most common landcover class in the grid cell based on the IGBP landcover map. The array order is longitude (ascending), followed by latitude (descending), and followed by IGBP land cover type descending dominance (only the first three types are listed) + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in UTC. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA retrievals within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Longitude of the center of the Earth based grid cell. + + + degrees_east + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -180. + + + 179.9989929 + + + -9999. + + + + + + + 65534 + + + Bit flags that represent the quality of the 3rd Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 3rd_Stokes_quality 3rd_Stokes_range 3rd_Stokes_RFI_detection 3rd_Stokes_RFI_correction 3rd_Stokes_NEDT 3rd_Stokes_direct_sun_correction 3rd_Stokes_reflected_sun_correction 3rd_Stokes_reflected_moon_correction 3rd_Stokes_direct_galaxy_correction 3rd_Stokes_reflected_galaxy_correction 3rd_Stokes_atmosphere_correction 3rd_Stokes_null_value_bit 3rd_Stokes_RFI_check 3rd_Stokes_RFI_clean + + + + + + + The measured opacity of the vegetation used in DCA retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + Bit flags that represent the quality of the vertical polarization brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Vertical_polarization_quality Vertical_polarization_range Vertical_polarization_RFI_detection Vertical_polarization_RFI_correction Vertical_polarization_NEDT Vertical_polarization_direct_sun_correction Vertical_polarization_reflected_sun_correction Vertical_polarization_reflected_moon_correction Vertical_polarization_direct_galaxy_correction Vertical_polarization_reflected_galaxy_correction Vertical_polarization_atmosphere_correction Vertical_polarization_Faraday_rotation_correction Vertical_polarization_null_value_bit Vertical_polarization_water_correction Vertical_polarization_RFI_check Vertical_polarization_RFI_clean + + + + + + + 0. + + + The fraction of the area of the 36 km grid cell that is covered by water based on the radar detection algorithm. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + Representative SCA-H soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/soil_moisture_pm + + + + + + + + 0. + + + The fraction of the grid cell that contains the most common land cover in that area based on the IGBP landcover map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + The measured opacity of the vegetation used in DCA retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/vegetation_opacity_dca_pm + + + + + + + 0. + + + Gain weighted fraction of static water within the radiometer horizontal polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + Weighted average of the longitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -180. + + + 179.9989929 + + + -9999. + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA retrievals within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/albedo_dca_pm + + + + + + + Representative measure of water in the vegetation within the 36 km grid cell. + + + kg/m**2 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 20. + + + -9999. + + + + + + + 0. + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-H retrievals within the grid cell. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + Latitude of the center of the Earth based grid cell. + + + degrees_north + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -90. + + + 90. + + + -9999. + + + + + + + Vertical polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + The measured opacity of the vegetation used in SCA-V retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + Indicates if the grid point lies on land (0) or water (1). + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 1 + + + 65534 + + + + + + + Temperature at land surface based on GMAO GEOS-5 data. + + + Kelvins + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 350. + + + -9999. + + + + diff --git a/tests/data/SC_SPL3SMP_008_prefetch.nc4 b/tests/data/SC_SPL3SMP_008_prefetch.nc4 new file mode 100644 index 0000000..f866858 Binary files /dev/null and b/tests/data/SC_SPL3SMP_008_prefetch.nc4 differ diff --git a/tests/data/SC_SPL3SMP_009.dmr b/tests/data/SC_SPL3SMP_009.dmr new file mode 100644 index 0000000..14d4977 --- /dev/null +++ b/tests/data/SC_SPL3SMP_009.dmr @@ -0,0 +1,2800 @@ + + + + + 3.21.0-428 + + + 3.21.0-428 + + + libdap-3.21.0-103 + + + build_dmrpp -c /tmp/bes_conf_PXTZ -f /usr/share/hyrax/DATA/SMAP_L3_SM_P_20150410_R19240_001.h5 -r /tmp/dmr__MLbLWr -u OPeNDAP_DMRpp_DATA_ACCESS_URL -M + + + + + 98a1a16758d855ddc3f64213ed0eb3a7 + + + e3fcd32b9b8c270a5851619117536eb1 + + + + + The SMAP observatory houses an L-band radiometer that operates at 1.414 GHz and an L-band radar that operates at 1.225 GHz. The instruments share a rotating reflector antenna with a 6 meter aperture that scans over a 1000 km swath. The bus is a 3 axis stabilized spacecraft that provides momentum compensation for the rotating antenna. + + + 14.60000038 + + + SMAP + + + + + JPL CL#14-2285, JPL 400-1567 + + + SMAP Handbook + + + 2014-07-01 + + + + + JPL CL#14-2285, JPL 400-1567 + + + SMAP Handbook + + + 2014-07-01 + + + + + The SMAP 1.414 GHz L-Band Radiometer + + + L-Band Radiometer + + + SMAP RAD + + + + + The SMAP 1.225 GHz L-Band Radar Instrument + + + L-Band Synthetic Aperture Radar + + + SMAP SAR + + + + + JPL CL#14-2285, JPL 400-1567 + + + SMAP Handbook + + + 2014-07-01 + + + + + + soil_moisture + + + + Percentage of EASE2 grid cells with Retrieved Soil Moistures outside the Acceptable Range. + + + Percentage of EASE2 grid cells with soil moisture measures that fall outside of a predefined acceptable range. + + + directInternal + + + percent + + + 100. + + + + + Percentage of EASE2 grid cells that lack soil moisture retrieval values relative to the total number of grid cells where soil moisture retrieval was attempted. + + + Percent of Missing Data + + + percent + + + 124.2959595 + + + directInternal + + + + + + eng + + + utf8 + + + 1.0 + + + Product Specification Document for the SMAP Level 3 Passive Soil Moisture Product (L3_SM_P) + + + 2013-02-08 + + + L3_SM_P + + + + + doi:10.5067/4XXOGX0OOW1S + + + SPL3SMP + + + SMAP + + + utf8 + + + National Aeronautics and Space Administration (NASA) + + + eng + + + 009 + + + Daily global composite of up-to 30 half-orbit L2_SM_P soil moisture estimates based on radiometer brightness temperature measurements acquired by the SMAP radiometer during ascending and descending half-orbits at approximately 6 PM and 6 AM local solar time. + + + onGoing + + + 2023-08-31 + + + The software that generates the Level 3 Soil Moisture Passive product and the data system that automates its production were designed and implemented + at the Jet Propulsion Laboratory, California Institute of Technology in Pasadena, California. + + + geoscientificInformation + + + The SMAP L3_SM_P algorithm provides daily global composite of soil moistures based on radiometer data on a 36 km grid. + + + SMAP L3 Radiometer Global Daily 36 km EASE-Grid Soil Moisture + + + National Snow and Ice Data Center + + + R19 + + + grid + + + The Calibration and Validation Version 2 Release of the SMAP Level 3 Daily Global Composite Passive Soil Moisture Science Processing Software. + + + + + SPL3SMP + + + utf8 + + + 026761d0-5866-418e-9acd-c1fcd308dc13 + + + eng + + + 1.8.13 + + + 009 + + + Daily global composite of up-to 15 half-orbit L2_SM_P soil moisture estimates based on radiometer brightness temperature measurements acquired by the SMAP radiometer during descending half-orbits at approximately 6 AM local solar time. + + + 2024-03-20 + + + onGoing + + + The software that generates the Level 3 SM_P product and the data system that automates its production were designed and implemented at the Jet Propulsion Laboratory, California Institute of Technology in Pasadena, California. + + + geoscientificInformation + + + The SMAP L3_SM_P effort provides soil moistures based on radiometer data on a 36 km grid. + + + HDF5 + + + SMAP_L3_SM_P_20150410_R19240_001.h5 + + + asNeeded + + + R19240 + + + Jet Propulsion Laboratory + + + 2016-05-01 + + + L3_SM_P + + + grid + + + The Calibration and Validation Version 2 Release of the SMAP Level 3 Daily Global Composite Passive Soil Moisture Science Processing Software. + + + + + Soil moisture is retrieved over land targets on the descending (AM) SMAP half-orbits when the SMAP spacecraft is travelling from North to South, while the SMAP instruments are operating in the nominal mode. The L3_SM_P product represents soil moisture retrieved over the entre UTC day. Retrievals are performed but flagged as questionable over urban areas, mountainous areas with high elevation variability, and areas with high ( &gt; 5 kg/m**2) vegetation water content; for retrievals using the high-resolution radar, cells in the nadir region are also flagged. Retrievals are inhibited for permanent snow/ice, frozen ground, and excessive static or transient open water in the cell, and for excessive RFI in the sensor data. + + + 180. + + + -180. + + + -85.04450226 + + + 85.04450226 + + + 2015-04-10T00:00:00.000Z + + + 2015-04-10T23:59:59.999Z + + + + + SMAP_L3_SM_P_20150410_R19240_001.qa + + + An ASCII product that contains statistical information on data product results. These statistics enable data producers and users to assess the quality of the data in the data product granule. + + + 2024-03-20 + + + + + 0 + + + 0 + + + 0 + + + 2 + + + SMAP Fixed Earth Grids, SMAP Science Document no: 033, May 11, 2009 + + + point + + + + 406 + + + 36. + + + + + EASE-Grid 2.0 + + + EASE-Grid 2.0: Incremental but Significant Improvements for Earth-Gridded Data Sets (ISPRS Int. J. Geo-Inf. 2012, 1, 32-45; doi:10.3390/ijgi1010032) + + + 2012-03-31 + + + + + 964 + + + 36. + + + + + The Equal-Area Scalable Earth Grid (EASE-Grid 2.0) is used for gridding satellite data sets. The EASE-Grid 2.0 is defined on the WGS84 ellipsoid to allow users to import data into standard GIS software formats such as GeoTIFF without reprojection. + + + Equal-Area Scalable Earth Grid + + + + + + 1015 + + + 1001 + + + + + + A configuration file that specifies the complete set of elements within the input Level 2 SM_P Product that the Radiometer Level 3_SM_P Science Processing Software (SPS) needs in order to function. + + + R19240 + + + SMAP_L3_SM_P_SPS_InputConfig_L2_SM_P.xml + + + 2024-03-20 + + + + + Precomputed longitude at each EASEGrid cell on 36-km grid on Global Cylindrical Projection + + + 002 + + + EZ2Lon_M36_002.float32 + + + 2013-05-09 + + + + + Passive soil moisture estimates onto a 36-km global Earth-fixed grid, based on radiometer measurements acquired when the SMAP spacecraft is travelling from North to South at approximately 6:00 AM local time. + + + SMAP_L2_SM_P_01001_A_20150409T233959_R19240_001.h5 + SMAP_L2_SM_P_01001_D_20150410T002914_R19240_001.h5 + SMAP_L2_SM_P_01002_A_20150410T011829_R19240_001.h5 + SMAP_L2_SM_P_01002_D_20150410T020739_R19240_001.h5 + SMAP_L2_SM_P_01003_A_20150410T025654_R19240_001.h5 + SMAP_L2_SM_P_01003_D_20150410T034609_R19240_001.h5 + SMAP_L2_SM_P_01004_A_20150410T043524_R19240_001.h5 + SMAP_L2_SM_P_01004_D_20150410T052435_R19240_001.h5 + SMAP_L2_SM_P_01005_A_20150410T061349_R19240_001.h5 + SMAP_L2_SM_P_01005_D_20150410T070304_R19240_001.h5 + SMAP_L2_SM_P_01006_A_20150410T075215_R19240_001.h5 + SMAP_L2_SM_P_01006_D_20150410T084130_R19240_001.h5 + SMAP_L2_SM_P_01007_A_20150410T093045_R19240_001.h5 + SMAP_L2_SM_P_01007_D_20150410T101959_R19240_001.h5 + SMAP_L2_SM_P_01008_A_20150410T110910_R19240_001.h5 + SMAP_L2_SM_P_01008_D_20150410T115825_R19240_001.h5 + SMAP_L2_SM_P_01009_A_20150410T124740_R19240_001.h5 + SMAP_L2_SM_P_01009_D_20150410T133655_R19240_001.h5 + SMAP_L2_SM_P_01010_A_20150410T142605_R19240_001.h5 + SMAP_L2_SM_P_01010_D_20150410T151520_R19240_001.h5 + SMAP_L2_SM_P_01011_A_20150410T160435_R19240_001.h5 + SMAP_L2_SM_P_01011_D_20150410T165346_R19240_001.h5 + SMAP_L2_SM_P_01012_A_20150410T174301_R19240_001.h5 + SMAP_L2_SM_P_01012_D_20150410T183216_R19240_001.h5 + SMAP_L2_SM_P_01013_A_20150410T192130_R19240_001.h5 + SMAP_L2_SM_P_01013_D_20150410T201041_R19240_001.h5 + SMAP_L2_SM_P_01014_A_20150410T205956_R19240_001.h5 + SMAP_L2_SM_P_01014_D_20150410T214911_R19240_001.h5 + SMAP_L2_SM_P_01015_A_20150410T223821_R19240_001.h5 + SMAP_L2_SM_P_01015_D_20150410T232736_R19240_001.h5 + + + doi:10.5067/K7Y2D8QQVZ4L + + + L2_SM_P + + + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + 2024-03-20 + + + 36. + + + + + A configuration file that specifies the source of the values for each of the data elements that comprise the metadata in the output Radiometer Level 3_SM_P product. + + + R19240 + + + SMAP_L3_SM_P_SPS_MetConfig_L2_SM_P.xml + + + 2024-03-20 + + + + + A configuration file that lists the entire content of the output Radiometer Level 3_SM_P_ product. + + + R19240 + + + SMAP_L3_SM_P_SPS_OutputConfig_L3_SM_P.xml + + + 2024-03-20 + + + + + A configuration file generated automatically within the SMAP data system that specifies all of the conditions required for each individual run of the Radiometer Level 3 SM P Science Processing Software (SPS). + + + R19240 + + + SMAP_L3_SM_P_SPS_RunConfig_20240320T172135232.xml + + + 2024-03-20 + + + + + + Soil moisture retrieved using default retrieval algorithm from brightness temperatures acquired by the SMAP radiometer during the spacecraft descending pass. Level 2 granule data are then mosaicked on a daily basis to form the Level 3 product. + + + 2024-03-20T17:21:35.232Z + + + Algorithm Theoretical Basis Document: SMAP L2 and L3 Radiometer Soil Moisture (Passive) Data Products: L2_SM_P &amp; L3_SM_P + + + 2000-01-01T11:58:55.816Z + + + 023 + + + L3_SM_P_SPS + + + 2021-08-17 + + + 015 + + + L3_SM_P_SPS + + + Version 1.1 + + + 2019-04-15 + + + 2015-10-30 + + + 026 + + + Level 3 soil moisture product is formed by mosaicking Level 2 soil moisture granule data acquired over one day. + + + Algorithm Theoretical Basis Document: SMAP L2 and L3 Radiometer Soil Moisture (Passive) Data Products: L2_SM_P &amp; L3_SM_P + + + 2451545. + + + J2000 + + + 2012-10-26 + + + Soil Moisture Active Passive Mission (SMAP) Science Data System (SDS) Operations Facility + + + Soil Moisture Active Passive (SMAP) Radiometer processing algorithm + + + Preliminary + + + + + + + + + Longitude of the center of the Earth based grid cell. + + + degrees_east + + + + + + + Latitude of the center of the Earth based grid cell. + + + degrees_north + + + + + + + 0. + + + The fraction of the area of the 36 km grid cell that is covered by static water based on a Digital Elevation Map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + + + Representative SCA-V soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + + + Representative angle between the antenna boresight vector and the normal to the Earth&apos;s surface for all footprints within the cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 90. + + + -9999. + + + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in UTC. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + + + The measured opacity of the vegetation used in the DCA retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + + + Bit flags that represent the quality of the horizontal polarization brightness temperature within each grid cell + + + 65534 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Horizontal_polarization_quality Horizontal_polarization_range Horizontal_polarization_RFI_detection Horizontal_polarization_RFI_correction Horizontal_polarization_NEDT Horizontal_polarization_direct_sun_correction Horizontal_polarization_reflected_sun_correction Horizontal_polarization_reflected_moon_correction Horizontal_polarization_direct_galaxy_correction Horizontal_polarization_reflected_galaxy_correction Horizontal_polarization_atmosphere_correction Horizontal_polarization_Faraday_rotation_correction Horizontal_polarization_null_value_bit Horizontal_polarization_water_correction Horizontal_polarization_RFI_check Horizontal_polarization_RFI_clean + + + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + + 254 + + + An enumerated type that specifies the most common landcover class in the grid cell based on the IGBP landcover map. The array order is longitude (ascending), followed by latitude (descending), and followed by IGBP land cover type descending dominance (only the first three types are listed) + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + + + The row index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 405 + + + 65534 + + + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Vertical polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Fourth stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Weighted average of the longitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + -180. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 179.9989929 + + + -9999. + + + + + + + + + The measured opacity of the vegetation used in the SCA-H retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + + + Bit flags that record the conditions and the quality of the SCA-H retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/roughness_coefficient + + + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-H within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + + 0. + + + The fraction of the grid cell that contains the most common land cover in that area based on the IGBP landcover map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + + + 0. + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-V within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + /Soil_Moisture_Retrieval_Data_AM/retrieval_qual_flag_dca + + + + + + + + + Representative measure of water in the vegetation within the 36 km grid cell. + + + kg/m**2 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 20. + + + -9999. + + + + + + + + + Vertical polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-V within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Representative SCA-H soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + + + Gain weighted fraction of static water within the radiometer horizontal polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-H within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + 0.01999999955 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.5 + + + -9999. + + + + + + + + + Third stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + + + Bit flags that represent the quality of the 3rd Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 3rd_Stokes_quality 3rd_Stokes_range 3rd_Stokes_RFI_detection 3rd_Stokes_RFI_correction 3rd_Stokes_NEDT 3rd_Stokes_direct_sun_correction 3rd_Stokes_reflected_sun_correction 3rd_Stokes_reflected_moon_correction 3rd_Stokes_direct_galaxy_correction 3rd_Stokes_reflected_galaxy_correction 3rd_Stokes_atmosphere_correction 3rd_Stokes_null_value_bit 3rd_Stokes_RFI_check 3rd_Stokes_RFI_clean + + + + + + + + + Bit flags that represent the quality of the 4th Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 4th_Stokes_quality 4th_Stokes_range 4th_Stokes_RFI_detection 4th_Stokes_RFI_correction 4th_Stokes_NEDT 4th_Stokes_direct_sun_correction 4th_Stokes_reflected_sun_correction 4th_Stokes_reflected_moon_correction 4th_Stokes_direct_galaxy_correction 4th_Stokes_reflected_galaxy_correction 4th_Stokes_atmosphere_correction 4th_Stokes_null_value_bit 4th_Stokes_RFI_check 4th_Stokes_RFI_clean + + + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + 0. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 330. + + + -9999. + + + + + + + + + Gain weighted fraction of static water within the radiometer vertical polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Indicates if the grid point lies on land (0) or water (1). + + + 65534 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 1 + + + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in seconds since noon on January 1, 2000 UTC. + + + seconds + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.90000000002 + + + 940000000. + + + -9999. + + + + + + + + + The measured opacity of the vegetation used in the DCA retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/vegetation_opacity + + + + + + + + + A unitless value that is indicative of aggregated bulk_density within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 2.650000095 + + + -9999. + + + + + + + + + Net uncertainty measure of soil moisture measure for the Earth based grid cell. - Calculation method is TBD. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 0.200000003 + + + -9999. + + + + + + + + + The fraction of the area of the 36 km grid cell that is covered by water based on the radar detection algorithm. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Bit flags that represent the quality of the vertical polarization brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Vertical_polarization_quality Vertical_polarization_range Vertical_polarization_RFI_detection Vertical_polarization_RFI_correction Vertical_polarization_NEDT Vertical_polarization_direct_sun_correction Vertical_polarization_reflected_sun_correction Vertical_polarization_reflected_moon_correction Vertical_polarization_direct_galaxy_correction Vertical_polarization_reflected_galaxy_correction Vertical_polarization_atmosphere_correction Vertical_polarization_Faraday_rotation_correction Vertical_polarization_null_value_bit Vertical_polarization_water_correction Vertical_polarization_RFI_check Vertical_polarization_RFI_clean + + + + + + + + + Weighted average of the latitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -90. + + + 90. + + + -9999. + + + + + + + + + The column index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 963 + + + 65534 + + + + + + + + + Temperature at land surface based on GMAO GEOS-5 data. + + + Kelvins + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 350. + + + -9999. + + + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + 0.01999999955 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.5 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/soil_moisture + + + + + + + + + Bit flags that record the conditions and the quality of the SCA-V retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + + + Fraction of the 36 km grid cell that is denoted as frozen. Based on binary flag that specifies freeze thaw conditions in each of the component 3 km grid cells. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + Bit flags that record ambient surface conditions for the grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s + + + 36_km_static_water_body 36_km_radar_water_body_detection 36_km_coastal_proximity 36_km_urban_area 36_km_precipitation 36_km_snow_or_ice 36_km_permanent_snow_or_ice 36_km_radiometer_frozen_ground 36_km_model_frozen_ground 36_km_mountainous_terrain 36_km_dense_vegetation 36_km_nadir_region + + + + + + + + + The measured opacity of the vegetation used in the SCA-V retrieval in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/albedo + + + + + + + + + A unitless value that is indicative of aggregated clay fraction within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + + + + + A unitless value that is indicative of aggregated bulk density within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 2.650000095 + + + -9999. + + + + + + + Representative angle between the antenna boresight vector and the normal to the Earth&apos;s surface for all footprints within the cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 90. + + + -9999. + + + + + + + The row index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 405 + + + 65534 + + + + + + + The fraction of the area of the 36 km grid cell that is covered by static water based on a Digital Elevation Map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Fraction of the 36 km grid cell that is denoted as frozen. Based on binary flag that specifies freeze thaw conditions in each of the component 3 km grid cells. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in DCA retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/roughness_coefficient_dca_pm + + + + + + + Bit flags that record ambient surface conditions for the grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s + + + 36_km_static_water_body 36_km_radar_water_body_detection 36_km_coastal_proximity 36_km_urban_area 36_km_precipitation 36_km_snow_or_ice 36_km_permanent_snow_or_ice 36_km_radar_frozen_ground 36_km_model_frozen_ground 36_km_mountainous_terrain 36_km_dense_vegetation 36_km_nadir_region + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the SCA-V retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-V retrievals within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + 0. + + + -9999. + + + Gain weighted fraction of static water within the radiometer vertical polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-V retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + 65534 + + + Bit flags that represent the quality of the 4th Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 4th_Stokes_quality 4th_Stokes_range 4th_Stokes_RFI_detection 4th_Stokes_RFI_correction 4th_Stokes_NEDT 4th_Stokes_direct_sun_correction 4th_Stokes_reflected_sun_correction 4th_Stokes_reflected_moon_correction 4th_Stokes_direct_galaxy_correction 4th_Stokes_reflected_galaxy_correction 4th_Stokes_atmosphere_correction 4th_Stokes_null_value_bit 4th_Stokes_RFI_check 4th_Stokes_RFI_clean + + + + + + + Third stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the DCA retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + /Soil_Moisture_Retrieval_Data_PM/retrieval_qual_flag_pm + + + + + + + Representative SCA-V soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + 65534 + + + 1s, 2s, 4s, 8s + + + Bit flags that record the conditions and the quality of the SCA-H retrieval algorithms that generate soil moisture for the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + Retrieval_recommended Retrieval_attempted Retrieval_success FT_retrieval_success + + + + + + + The measured opacity of the vegetation used in SCA-H retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + Kelvin + + + 0. + + + Vertical polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 330. + + + -9999. + + + + + + + A unitless value that is indicative of bare soil roughness used in SCA-H retrievals within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Bit flags that represent the quality of the horizontal polarization brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Horizontal_polarization_quality Horizontal_polarization_range Horizontal_polarization_RFI_detection Horizontal_polarization_RFI_correction Horizontal_polarization_NEDT Horizontal_polarization_direct_sun_correction Horizontal_polarization_reflected_sun_correction Horizontal_polarization_reflected_moon_correction Horizontal_polarization_direct_galaxy_correction Horizontal_polarization_reflected_galaxy_correction Horizontal_polarization_atmosphere_correction Horizontal_polarization_Faraday_rotation_correction Horizontal_polarization_null_value_bit Horizontal_polarization_water_correction Horizontal_polarization_RFI_check Horizontal_polarization_RFI_clean + + + + + + + A unitless value that is indicative of aggregated clay fraction within the 36 km grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Weighted average of the latitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -90. + + + 90. + + + -9999. + + + + + + + The column index of the 36 km EASE grid cell that contains the associated data. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 963 + + + 65534 + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in seconds since noon on January 1, 2000 UTC. + + + seconds + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.90000000002 + + + 940000000. + + + -9999. + + + + + + + Fourth stokes parameter for each 36 km grid cell calculated with an adjustment for the presence of water bodies + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + Net uncertainty measure of soil moisture measure for the Earth based grid cell. - Calculation method is TBD. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 0.200000003 + + + -9999. + + + + + + + + 254 + + + An enumerated type that specifies the most common landcover class in the grid cell based on the IGBP landcover map. The array order is longitude (ascending), followed by latitude (descending), and followed by IGBP land cover type descending dominance (only the first three types are listed) + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + Arithmetic average of the acquisition time of all of the brightness temperature footprints with a center that falls within the EASE grid cell in UTC. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA retrievals within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + + + + + Longitude of the center of the Earth based grid cell. + + + degrees_east + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -180. + + + 179.9989929 + + + -9999. + + + + + + + 65534 + + + Bit flags that represent the quality of the 3rd Stokes brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 4096s, 16384s, 32768s + + + 3rd_Stokes_quality 3rd_Stokes_range 3rd_Stokes_RFI_detection 3rd_Stokes_RFI_correction 3rd_Stokes_NEDT 3rd_Stokes_direct_sun_correction 3rd_Stokes_reflected_sun_correction 3rd_Stokes_reflected_moon_correction 3rd_Stokes_direct_galaxy_correction 3rd_Stokes_reflected_galaxy_correction 3rd_Stokes_atmosphere_correction 3rd_Stokes_null_value_bit 3rd_Stokes_RFI_check 3rd_Stokes_RFI_clean + + + + + + + The measured opacity of the vegetation used in DCA retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + Bit flags that represent the quality of the vertical polarization brightness temperature within each grid cell + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 65534 + + + 1s, 2s, 4s, 8s, 16s, 32s, 64s, 128s, 256s, 512s, 1024s, 2048s, 4096s, 8192s, 16384s, 32768s + + + Vertical_polarization_quality Vertical_polarization_range Vertical_polarization_RFI_detection Vertical_polarization_RFI_correction Vertical_polarization_NEDT Vertical_polarization_direct_sun_correction Vertical_polarization_reflected_sun_correction Vertical_polarization_reflected_moon_correction Vertical_polarization_direct_galaxy_correction Vertical_polarization_reflected_galaxy_correction Vertical_polarization_atmosphere_correction Vertical_polarization_Faraday_rotation_correction Vertical_polarization_null_value_bit Vertical_polarization_water_correction Vertical_polarization_RFI_check Vertical_polarization_RFI_clean + + + + + + + 0. + + + The fraction of the area of the 36 km grid cell that is covered by water based on the radar detection algorithm. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + Representative SCA-H soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + + + + + Representative DCA soil moisture measurement for the Earth based grid cell. + + + cm**3/cm**3 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0.01999999955 + + + 0.5 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/soil_moisture_pm + + + + + + + + 0. + + + The fraction of the grid cell that contains the most common land cover in that area based on the IGBP landcover map. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + The measured opacity of the vegetation used in DCA retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/vegetation_opacity_dca_pm + + + + + + + 0. + + + Gain weighted fraction of static water within the radiometer horizontal polarization brightness temperature antenna pattern in 36 km Earth grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 1. + + + -9999. + + + + + + + Weighted average of the longitude of the center of the brightness temperature footprints that fall within the EASE grid cell. + + + degrees + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -180. + + + 179.9989929 + + + -9999. + + + + + + + Diffuse reflecting power of the Earth&apos;s surface used in DCA retrievals within the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_PM/albedo_dca_pm + + + + + + + Representative measure of water in the vegetation within the 36 km grid cell. + + + kg/m**2 + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 20. + + + -9999. + + + + + + + 0. + + + Diffuse reflecting power of the Earth&apos;s surface used in SCA-H retrievals within the grid cell. + + + 1. + + + -9999. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + + + + + Horizontal polarization brightness temperature in 36 km Earth grid cell before adjustment for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + Latitude of the center of the Earth based grid cell. + + + degrees_north + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -90. + + + 90. + + + -9999. + + + + + + + Vertical polarization brightness temperature in 36 km Earth grid cell adjusted for the presence of water bodies. + + + Kelvin + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 330. + + + -9999. + + + + + + + The measured opacity of the vegetation used in SCA-V retrievals in the grid cell. + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + -999999.875 + + + 999999.875 + + + -9999. + + + + + + + Indicates if the grid point lies on land (0) or water (1). + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0 + + + 1 + + + 65534 + + + + + + + Temperature at land surface based on GMAO GEOS-5 data. + + + Kelvins + + + /Soil_Moisture_Retrieval_Data_AM/latitude /Soil_Moisture_Retrieval_Data_AM/longitude + + + 0. + + + 350. + + + -9999. + + + + diff --git a/tests/unit/test_coordinate_utilities.py b/tests/unit/test_coordinate_utilities.py new file mode 100644 index 0000000..56e9ad9 --- /dev/null +++ b/tests/unit/test_coordinate_utilities.py @@ -0,0 +1,267 @@ +from logging import getLogger +from os.path import exists +from shutil import copy, rmtree +from tempfile import mkdtemp +from unittest import TestCase +from unittest.mock import ANY, patch + +import numpy as np +from harmony.util import config +from netCDF4 import Dataset +from numpy.testing import assert_array_equal +from varinfo import VarInfoFromDmr + +from hoss.coordinate_utilities import ( + get_coordinate_variables, + get_dimension_scale_from_dimvalues, + get_fill_values_for_coordinates, + get_lat_lon_arrays, + get_override_projected_dimension_name, + get_override_projected_dimensions, + get_row_col_sizes_from_coordinate_datasets, + get_two_valid_geo_grid_points, + get_valid_indices, + get_valid_indices_in_dataset, + get_variables_with_anonymous_dims, + get_x_y_values_from_geographic_points, + update_dimension_variables, +) +from hoss.exceptions import ( + CannotComputeDimensionResolution, + InvalidCoordinateVariable, + MissingCoordinateVariable, +) + + +class TestCoordinateUtilities(TestCase): + """A class for testing functions in the `hoss.coordinate_utilities` + module. + + """ + + @classmethod + def setUpClass(cls): + """Create fixtures that can be reused for all tests.""" + cls.config = config(validate=False) + cls.logger = getLogger('tests') + cls.varinfo = VarInfoFromDmr( + 'tests/data/SC_SPL3SMP_008.dmr', + 'SPL3SMP', + config_file='hoss/hoss_config.json', + ) + cls.nc4file = 'tests/data/SC_SPL3SMP_008_prefetch.nc4' + cls.latitude = '/Soil_Moisture_Retrieval_Data_AM/latitude' + cls.longitude = '/Soil_Moisture_Retrieval_Data_AM/longitude' + + cls.lon_arr = np.array( + [ + [-179.3, -120.2, -60.6, -9999, -9999, -9999, 80.2, 120.6, 150.5, 178.4], + [-179.3, -120.2, -60.6, -9999, -9999, -9999, 80.2, 120.6, 150.5, 178.4], + [-179.3, -120.2, -60.6, -9999, -9999, -9999, 80.2, 120.6, 150.5, 178.4], + [-179.3, -120.2, -60.6, -9999, -9999, -9999, 80.2, 120.6, 150.5, 178.4], + [-179.3, -120.2, -60.6, -9999, -9999, -9999, 80.2, 120.6, 150.5, 178.4], + ] + ) + + cls.lat_arr = np.array( + [ + [89.3, 89.3, -9999, 89.3, 89.3, 89.3, -9999, 89.3, 89.3, 89.3], + [50.3, 50.3, 50.3, 50.3, 50.3, 50.3, -9999, 50.3, 50.3, 50.3], + [1.3, 1.3, 1.3, 1.3, 1.3, 1.3, -9999, -9999, 1.3, 1.3], + [-9999, -60.2, -60.2, -9999, -9999, -9999, -60.2, -60.2, -60.2, -60.2], + [-88.1, -88.1, -88.1, -9999, -9999, -9999, -88.1, -88.1, -88.1, -88.1], + ] + ) + + cls.lon_arr_reversed = np.array( + [ + [ + -179.3, + -179.3, + -179.3, + -179.3, + -9999, + -9999, + -179.3, + -179.3, + -179.3, + -179.3, + ], + [ + -120.2, + -120.2, + -120.2, + -9999, + -9999, + -120.2, + -120.2, + -120.2, + -120.2, + -120.2, + ], + [20.6, 20.6, 20.6, 20.6, 20.6, 20.6, 20.6, 20.6, -9999, -9999], + [150.5, 150.5, 150.5, 150.5, 150.5, 150.5, -9999, -9999, 150.5, 150.5], + [178.4, 178.4, 178.4, 178.4, 178.4, 178.4, 178.4, -9999, 178.4, 178.4], + ] + ) + + cls.lat_arr_reversed = np.array( + [ + [89.3, 79.3, -9999, 59.3, 29.3, 2.1, -9999, -59.3, -79.3, -89.3], + [89.3, 79.3, 60.3, 59.3, 29.3, 2.1, -9999, -59.3, -79.3, -89.3], + [89.3, -9999, 60.3, 59.3, 29.3, 2.1, -9999, -9999, -9999, -89.3], + [-9999, 79.3, -60.3, -9999, -9999, -9999, -60.2, -59.3, -79.3, -89.3], + [-89.3, 79.3, -60.3, -9999, -9999, -9999, -60.2, -59.3, -79.3, -9999], + ] + ) + + def setUp(self): + """Create fixtures that should be unique per test.""" + + def tearDown(self): + """Remove per-test fixtures.""" + + def get_coordinate_variables(self): + """Ensure that the correct coordinate variables are + retrieved for the reqquested science variable + + """ + + requested_science_variables = set( + '/Soil_Moisture_Retrieval_Data_AM/surface_flag', + '/Soil_Moisture_Retrieval_Data_AM/landcover_class', + '/Soil_Moisture_Retrieval_Data_PM/surface_flag_pm', + ) + + expected_coordinate_variables = tuple([self.latitude], [self.longitude]) + + with self.subTest('Retrieves expected coordinates for the requested variable'): + self.assertTupleEqual( + get_coordinate_variables(self.varinfo, requested_science_variables), + expected_coordinate_variables, + ) + + def test_get_dimension_scale_from_dimvalues(self): + """Ensure that the dimension scale generated from the + provided dimension values are accurate for ascending and + descending scales + """ + + dim_values_asc = np.array([2, 4]) + dim_indices_asc = np.array([0, 1]) + dim_size_asc = 12 + expected_dim_asc = np.array([2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]) + + dim_values_desc = np.array([100, 70]) + dim_indices_desc = np.array([2, 5]) + dim_size_desc = 10 + expected_dim_desc = np.array([120, 110, 100, 90, 80, 70, 60, 50, 40, 30]) + + dim_values_invalid = np.array([2, 2]) + dim_indices_asc = np.array([0, 1]) + dim_size_asc = 12 + + dim_values_desc = np.array([100, 70]) + dim_indices_invalid = np.array([5, 5]) + dim_size_desc = 10 + + with self.subTest('valid ascending dim scale'): + dim_scale_values = get_dimension_scale_from_dimvalues( + dim_values_asc, dim_indices_asc, dim_size_asc + ) + self.assertTrue(np.array_equal(dim_scale_values, expected_dim_asc)) + with self.subTest('valid descending dim scale'): + dim_scale_values = get_dimension_scale_from_dimvalues( + dim_values_desc, dim_indices_desc, dim_size_desc + ) + self.assertTrue(np.array_equal(dim_scale_values, expected_dim_desc)) + + with self.subTest('invalid dimension values'): + with self.assertRaises(CannotComputeDimensionResolution) as context: + get_dimension_scale_from_dimvalues( + dim_values_invalid, dim_indices_asc, dim_size_asc + ) + self.assertEqual( + context.exception.message, + 'Cannot compute the dimension resolution for ' + 'dim_value: "2" dim_index: "0"', + ) + with self.subTest('invalid dimension indices'): + with self.assertRaises(CannotComputeDimensionResolution) as context: + get_dimension_scale_from_dimvalues( + dim_values_desc, dim_indices_invalid, dim_size_desc + ) + self.assertEqual( + context.exception.message, + 'Cannot compute the dimension resolution for ' + 'dim_value: "100" dim_index: "5"', + ) + + def test_get_valid_indices(self): + """Ensure that latitude and longitude values are correctly identified as + ascending or descending. + + """ + expected_valid_indices_lat_arr = np.array([0, 1, 2, 3, 4]) + expected_valid_indices_lon_arr = np.array([0, 1, 2, 6, 7, 8, 9]) + + fill_array = np.array([-9999.0, -9999.0, -9999.0, -9999.0]) + with self.subTest('valid indices with no fill values configured'): + valid_indices_lat_arr = get_valid_indices( + self.lat_arr[:, -1], None, 'latitude' + ) + self.assertTrue( + np.array_equal(valid_indices_lat_arr, expected_valid_indices_lat_arr) + ) + + with self.subTest('valid indices with fill values configured'): + valid_indices_lon_arr = get_valid_indices( + self.lon_arr[0, :], -9999.0, 'longitude' + ) + self.assertTrue( + np.array_equal(valid_indices_lon_arr, expected_valid_indices_lon_arr) + ) + + with self.subTest('all fill values - no valid indices'): + valid_indices = get_valid_indices(fill_array, -9999.0, 'longitude') + self.assertTrue(valid_indices.size == 0) + + def test_get_two_valid_geo_grid_points(self): + """Ensure that two valid lat/lon points returned by the method + with a set of lat/lon coordinates as input + + """ + lat_fill = -9999.0 + lon_fill = -9999.0 + row_size = 406 + col_size = 964 + + expected_geo_grid_points = [(-179.3, 89.3), (-120.2, -88.1)] + expected_geo_grid_points_reversed = [(-179.3, 89.3), (178.4, 79.3)] + with self.subTest('Get two valid geo grid points from coordinates'): + actual_geo_grid_points = get_two_valid_geo_grid_points( + self.lat_arr, self.lon_arr, lat_fill, lon_fill, row_size, col_size + ) + for actual_geo_grid_point, expected_geo_grid_point in zip( + actual_geo_grid_points.values(), expected_geo_grid_points + ): + self.assertEqual(actual_geo_grid_point, expected_geo_grid_point) + + with self.subTest('Get two valid geo grid points from reversed coordinates'): + actual_geo_grid_points = get_two_valid_geo_grid_points( + self.lat_arr_reversed, + self.lon_arr_reversed, + lat_fill, + lon_fill, + row_size, + col_size, + ) + for actual_geo_grid_point, expected_geo_grid_point in zip( + actual_geo_grid_points.values(), expected_geo_grid_points_reversed + ): + self.assertEqual(actual_geo_grid_point, expected_geo_grid_point) + + +# get_dimension_scale_from_dimvalues( +# dim_values: ndarray, dim_indices: ndarray, dim_size: float +# ) -> ndarray: diff --git a/tests/unit/test_dimension_utilities.py b/tests/unit/test_dimension_utilities.py index 5ad7a21..9be9f07 100644 --- a/tests/unit/test_dimension_utilities.py +++ b/tests/unit/test_dimension_utilities.py @@ -23,12 +23,12 @@ get_dimension_indices_from_bounds, get_dimension_indices_from_values, get_fill_slice, + get_prefetch_variables, get_requested_index_ranges, is_almost_in, is_dimension_ascending, is_index_subset, needs_bounds, - prefetch_dimension_variables, write_bounds, ) from hoss.exceptions import InvalidNamedDimension, InvalidRequestedRange @@ -328,7 +328,7 @@ def test_get_fill_slice(self): @patch('hoss.dimension_utilities.add_bounds_variables') @patch('hoss.dimension_utilities.get_opendap_nc4') - def test_prefetch_dimension_variables( + def test_get_prefetch_variables( self, mock_get_opendap_nc4, mock_add_bounds_variables ): """Ensure that when a list of required variables is specified, a @@ -349,7 +349,7 @@ def test_prefetch_dimension_variables( required_dimensions = {'/latitude', '/longitude', '/time'} self.assertEqual( - prefetch_dimension_variables( + get_prefetch_variables( url, self.varinfo, required_variables, @@ -569,7 +569,7 @@ def test_prefetch_dimensions_with_bounds(self, mock_get_opendap_nc4): } self.assertEqual( - prefetch_dimension_variables( + get_prefetch_variables( url, self.varinfo_with_bounds, required_variables, diff --git a/tests/unit/test_projection_utilities.py b/tests/unit/test_projection_utilities.py index 0da8f66..fe5b183 100644 --- a/tests/unit/test_projection_utilities.py +++ b/tests/unit/test_projection_utilities.py @@ -194,6 +194,26 @@ def test_get_variable_crs(self): 'present in granule .dmr file.', ) + with self.subTest('grid_mapping override with json configuration'): + smap_varinfo = VarInfoFromDmr( + 'tests/data/SC_SPL3SMP_009.dmr', + 'SPL3SMP', + 'hoss/hoss_config.json', + ) + expected_crs = CRS.from_cf( + { + 'false_easting': 0.0, + 'false_northing': 0.0, + 'longitude_of_central_meridian': 0.0, + 'standard_parallel': 30.0, + 'grid_mapping_name': 'lambert_cylindrical_equal_area', + } + ) + actual_crs = get_variable_crs( + '/Soil_Moisture_Retrieval_Data_AM/surface_flag', smap_varinfo + ) + self.assertEqual(actual_crs, expected_crs) + def test_get_projected_x_y_extents(self): """Ensure that the expected values for the x and y dimension extents are recovered for a known projected grid and requested input. diff --git a/tests/unit/test_spatial.py b/tests/unit/test_spatial.py index e5ee6d3..cf83472 100644 --- a/tests/unit/test_spatial.py +++ b/tests/unit/test_spatial.py @@ -11,12 +11,14 @@ from varinfo import VarInfoFromDmr from hoss.bbox_utilities import BBox +from hoss.coordinate_utilities import update_dimension_variables from hoss.spatial import ( get_bounding_box_longitudes, get_geographic_index_range, get_longitude_in_grid, get_projected_x_y_index_ranges, get_spatial_index_ranges, + get_x_y_index_ranges_from_coordinates, ) @@ -182,6 +184,123 @@ def test_get_spatial_index_ranges_geographic(self): {'/latitude': (5, 44), '/longitude': (160, 199)}, ) + @patch('hoss.spatial.get_dimension_index_range') + @patch('hoss.spatial.get_projected_x_y_extents') + def test_get_x_y_index_ranges_from_coordinates( + self, + mock_get_x_y_extents, + mock_get_dimension_index_range, + ): + """Ensure that x and y index ranges are only requested only when there are + no projected dimensions and when there are coordinate datasets, + and the values have not already been calculated. + + The example used in this test is for the SMAP SPL3SMP collection, + (SMAP L3 Radiometer Global Daily 36 km EASE-Grid Soil Moisture) + which has a Equal-Area Scalable Earth Grid (EASE-Grid 2.0) CRS for + a projected grid which is lambert_cylindrical_equal_area projection + + """ + smap_varinfo = VarInfoFromDmr( + 'tests/data/SC_SPL3SMP_008.dmr', + 'SPL3SMP', + 'hoss/hoss_config.json', + ) + smap_file_path = 'tests/data/SC_SPL3SMP_008_prefetch.nc4' + expected_index_ranges = {'projected_x': (487, 595), 'projected_y': (9, 38)} + bbox = BBox(2, 54, 42, 72) + + latitude_coordinate = smap_varinfo.get_variable( + '/Soil_Moisture_Retrieval_Data_AM/latitude' + ) + longitude_coordinate = smap_varinfo.get_variable( + '/Soil_Moisture_Retrieval_Data_AM/longitude' + ) + + crs = CRS.from_cf( + { + 'false_easting': 0.0, + 'false_northing': 0.0, + 'longitude_of_central_meridian': 0.0, + 'standard_parallel': 30.0, + 'grid_mapping_name': 'lambert_cylindrical_equal_area', + } + ) + + x_y_extents = { + 'x_min': 192972.56050179302, + 'x_max': 4052423.7705376535, + 'y_min': 5930779.396449475, + 'y_max': 6979878.9118312765, + } + + mock_get_x_y_extents.return_value = x_y_extents + + # When ranges are derived, they are first calculated for x, then y: + mock_get_dimension_index_range.side_effect = [(487, 595), (9, 38)] + + with self.subTest( + 'Projected grid from coordinates gets expected dimension ranges' + ): + with Dataset(smap_file_path, 'r') as smap_prefetch: + self.assertDictEqual( + get_x_y_index_ranges_from_coordinates( + '/Soil_Moisture_Retrieval_Data_AM/surface_flag', + smap_varinfo, + smap_prefetch, + latitude_coordinate, + longitude_coordinate, + {}, + bounding_box=bbox, + shape_file_path=None, + ), + expected_index_ranges, + ) + + mock_get_x_y_extents.assert_called_once_with( + ANY, ANY, crs, shape_file=None, bounding_box=bbox + ) + + self.assertEqual(mock_get_dimension_index_range.call_count, 2) + mock_get_dimension_index_range.assert_has_calls( + [ + call( + ANY, + x_y_extents['x_min'], + x_y_extents['x_max'], + bounds_values=None, + ), + call( + ANY, + x_y_extents['y_min'], + x_y_extents['y_max'], + bounds_values=None, + ), + ] + ) + + mock_get_x_y_extents.reset_mock() + mock_get_dimension_index_range.reset_mock() + + with self.subTest('Function does not rederive known index ranges'): + with Dataset(smap_file_path, 'r') as smap_prefetch: + self.assertDictEqual( + get_x_y_index_ranges_from_coordinates( + '/Soil_Moisture_Retrieval_Data_AM/surface_flag', + smap_varinfo, + smap_prefetch, + latitude_coordinate, + longitude_coordinate, + expected_index_ranges, + bounding_box=bbox, + shape_file_path=None, + ), + {}, + ) + + mock_get_x_y_extents.assert_not_called() + mock_get_dimension_index_range.assert_not_called() + @patch('hoss.spatial.get_dimension_index_range') @patch('hoss.spatial.get_projected_x_y_extents') def test_get_projected_x_y_index_ranges( diff --git a/tests/unit/test_subset.py b/tests/unit/test_subset.py index abbb5f1..7c6e979 100644 --- a/tests/unit/test_subset.py +++ b/tests/unit/test_subset.py @@ -62,7 +62,7 @@ def tearDown(self): @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_granule_not_geo( self, @@ -126,7 +126,7 @@ def test_subset_granule_not_geo( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_granule_geo( self, @@ -216,7 +216,7 @@ def test_subset_granule_geo( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_non_geo_no_variables( self, @@ -290,7 +290,7 @@ def test_subset_non_geo_no_variables( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_geo_no_variables( self, @@ -404,7 +404,7 @@ def test_subset_geo_no_variables( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_non_variable_dimensions( self, @@ -537,7 +537,7 @@ def test_subset_non_variable_dimensions( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_bounds_reference( self, @@ -638,7 +638,7 @@ def test_subset_bounds_reference( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_temporal( self, @@ -742,7 +742,7 @@ def test_subset_temporal( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_geo_temporal( self, @@ -860,7 +860,7 @@ def test_subset_geo_temporal( @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') @patch('hoss.subset.get_request_shape_file') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_granule_shape( self, @@ -971,7 +971,7 @@ def test_subset_granule_shape( @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') @patch('hoss.subset.get_request_shape_file') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_granule_shape_and_bbox( self, @@ -1083,7 +1083,7 @@ def test_subset_granule_shape_and_bbox( @patch('hoss.subset.get_requested_index_ranges') @patch('hoss.subset.get_temporal_index_ranges') @patch('hoss.subset.get_spatial_index_ranges') - @patch('hoss.subset.prefetch_dimension_variables') + @patch('hoss.subset.get_prefetch_variables') @patch('hoss.subset.get_varinfo') def test_subset_granule_geo_named( self,