diff --git a/hoss/coordinate_utilities.py b/hoss/coordinate_utilities.py new file mode 100644 index 0000000..2fc7bcb --- /dev/null +++ b/hoss/coordinate_utilities.py @@ -0,0 +1,232 @@ +""" 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 Set, Tuple + +import numpy as np +from netCDF4 import Dataset +from numpy import ndarray +from varinfo import VariableFromDmr, VarInfoFromDmr + +from hoss.exceptions import ( + CannotComputeDimensionResolution, + IrregularCoordinateVariables, + MissingCoordinateVariable, +) + + +def get_override_projected_dimension_names( + varinfo: VarInfoFromDmr, variable_name: str +) -> str: + """returns the x-y projection variable names that would + match the group of geo coordinate names. The coordinate + variable name gets converted to 'projected_y' dimension scale + and 'projected_x' + + """ + override_variable = varinfo.get_variable(variable_name) + + if override_variable is not None and ( + override_variable.is_latitude() or override_variable.is_longitude() + ): + projected_dimension_names = [ + f'{override_variable.group_path}/projected_y', + f'{override_variable.group_path}/projected_x', + ] + else: + raise MissingCoordinateVariable(override_variable.full_name_path) + + return projected_dimension_names + + +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] + ) + + override_dimensions = [] + if latitude_coordinates and longitude_coordinates: + # there should be only 1 lat and lon coordinate for one variable + override_dimensions = get_override_projected_dimension_names( + varinfo, latitude_coordinates[0] + ) + + # if the override is the variable + elif ( + varinfo.get_variable(variable_name).is_latitude() + or varinfo.get_variable(variable_name).is_longitude() + ): + override_dimensions = get_override_projected_dimension_names( + varinfo, variable_name + ) + 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 = sorted( + 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 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 + + """ + if lat_arr.ndim > 1 and lon_arr.shape == lat_arr.shape: + col_size = lat_arr.shape[1] + row_size = lat_arr.shape[0] + elif ( + lat_arr.ndim == 1 + and lon_arr.ndim == 1 + and lat_arr.size > 0 + and lon_arr.size > 0 + ): + col_size = lon_arr.size + row_size = lat_arr.size + else: + raise IrregularCoordinateVariables(lon_arr.shape, lat_arr.shape) + 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][:] + except Exception as exception: + raise MissingCoordinateVariable( + latitude_coordinate.full_name_path + ) from exception + + try: + lon_arr = prefetch_dataset[longitude_coordinate.full_name_path][:] + except Exception as exception: + raise MissingCoordinateVariable( + longitude_coordinate.full_name_path + ) from exception + + return lat_arr, lon_arr + + +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( + 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_value_for_coordinate( + coordinate: VariableFromDmr, +) -> 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 + """ + + fill_value = coordinate.get_attribute_value('_FillValue') + if fill_value is not None: + return float(fill_value) + return fill_value 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..7a4caea 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,84 @@ }, "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,12 +290,40 @@ }, "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." + }, + { + "Applicability": { + "Mission": "SMAP", + "ShortNamePath": "SPL3SMP", + "Variable_Pattern": "/Soil_Moisture_Retrieval_Data_PM/.*" + }, + "Attributes": [ + { + "Name": "coordinates", + "Value": "/Soil_Moisture_Retrieval_Data_PM/latitude_pm, /Soil_Moisture_Retrieval_Data_PM/longitude_pm" + } + ], + "_Description": "Ensure variables in /Soil_Moisture_Retrieval_Data_PM group point to correct coordinate variables." + }, { "Applicability": { "Mission": "SMAP", 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/unit/test_coordinate_utilities.py b/tests/unit/test_coordinate_utilities.py new file mode 100644 index 0000000..88db1d5 --- /dev/null +++ b/tests/unit/test_coordinate_utilities.py @@ -0,0 +1,431 @@ +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_value_for_coordinate, + get_lat_lon_arrays, + get_override_projected_dimension_names, + get_override_projected_dimensions, + get_row_col_sizes_from_coordinate_datasets, + get_valid_indices, + get_variables_with_anonymous_dims, +) +from hoss.exceptions import ( + CannotComputeDimensionResolution, + InvalidCoordinateVariable, + IrregularCoordinateVariables, + 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 test_create_dimension_scales_from_coordinates(self): + """Ensure that the dimension scales created from the + coordinates are as expected + """ + + def test_get_coordinate_variables(self): + """Ensure that the correct coordinate variables are + retrieved for the reqquested science variable + + """ + requested_science_variables = { + '/Soil_Moisture_Retrieval_Data_AM/surface_flag', + '/Soil_Moisture_Retrieval_Data_PM/surface_flag_pm', + } + expected_coordinate_variables = ( + [ + '/Soil_Moisture_Retrieval_Data_AM/latitude', + '/Soil_Moisture_Retrieval_Data_PM/latitude_pm', + ], + [ + '/Soil_Moisture_Retrieval_Data_AM/longitude', + '/Soil_Moisture_Retrieval_Data_PM/longitude_pm', + ], + ) + + with self.subTest('Retrieves expected coordinates for the requested variable'): + actual_coordinate_variables = get_coordinate_variables( + self.varinfo, requested_science_variables + ) + self.assertTupleEqual( + actual_coordinate_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_fill_value_for_coordinate(self): + """Ensure that the fill values for the coordinates + are correctly returned + + """ + latitude_coordinate = self.varinfo.get_variable(self.latitude) + with self.subTest('Retrieves expected fill value for the latitude variable'): + self.assertEqual( + get_fill_value_for_coordinate(latitude_coordinate), -9999.0 + ) + with self.subTest('Returns None when there is no fill value for a variable'): + self.assertEqual( + get_fill_value_for_coordinate( + self.varinfo.get_variable( + '/Soil_Moisture_Retrieval_Data_AM/tb_time_utc' + ) + ), + None, + ) + + def test_get_lat_lon_arrays(self): + """Ensures that the expected lat/lon arrays are retrieved + for the coordinate variables + """ + prefetch_dataset = Dataset(self.nc4file, 'r') + expected_shape = (406, 964) + with self.subTest('Expected lat/lon arrays'): + lat_prefetch_arr, lon_prefetch_arr = get_lat_lon_arrays( + prefetch_dataset, + self.varinfo.get_variable(self.latitude), + self.varinfo.get_variable(self.longitude), + ) + self.assertTupleEqual(lat_prefetch_arr.shape, expected_shape) + self.assertTupleEqual(lon_prefetch_arr.shape, expected_shape) + + with self.subTest('Missing coordinate'): + with self.assertRaises(MissingCoordinateVariable) as context: + lat_prefetch_arr, lon_prefetch_arr = get_lat_lon_arrays( + prefetch_dataset, + self.varinfo.get_variable( + '/Soil_Moisture_Retrieval_Data_AM/latitude_centroid' + ), + self.varinfo.get_variable( + '/Soil_Moisture_Retrieval_Data_AM/longitude_centroid' + ), + ) + self.assertEqual( + context.exception.message, + 'Coordinate: "/Soil_Moisture_Retrieval_Data_AM/latitude_centroid" is ' + 'not present in source granule file.', + ) + + def test_get_override_projected_dimension_names(self): + """Ensure that the expected projected dimension name + is returned for the coordinate variables + """ + + expected_projected_names = [ + '/Soil_Moisture_Retrieval_Data_AM/projected_y', + '/Soil_Moisture_Retrieval_Data_AM/projected_x', + ] + + with self.subTest( + 'Retrieves expected projected dimension names for a science variable' + ): + self.assertListEqual( + get_override_projected_dimension_names(self.varinfo, self.latitude), + expected_projected_names, + ) + + with self.subTest( + 'Retrieves expected dimension names for the longitude variable' + ): + self.assertEqual( + get_override_projected_dimension_names(self.varinfo, self.longitude), + expected_projected_names, + ) + + with self.subTest('Raises exception for missing coordinate variable'): + with self.assertRaises(MissingCoordinateVariable) as context: + get_override_projected_dimension_names( + self.varinfo, '/Soil_Moisture_Retrieval_Data_AM/longitude_centroid' + ) + self.assertEqual( + context.exception.message, + 'Coordinate: "/Soil_Moisture_Retrieval_Data_AM/latitude_centroid" is ' + 'not present in source granule file.', + ) + + def test_get_override_projected_dimensions(self): + """Ensure that the expected projected dimension name + is returned for the coordinate variables + """ + + expected_override_dimensions_AM = [ + '/Soil_Moisture_Retrieval_Data_AM/projected_y', + '/Soil_Moisture_Retrieval_Data_AM/projected_x', + ] + expected_override_dimensions_PM = [ + '/Soil_Moisture_Retrieval_Data_PM/projected_y', + '/Soil_Moisture_Retrieval_Data_PM/projected_x', + ] + + with self.subTest( + 'Retrieves expected override dimensions for the science variable' + ): + self.assertEqual( + get_override_projected_dimensions( + self.varinfo, '/Soil_Moisture_Retrieval_Data_AM/surface_flag' + ), + expected_override_dimensions_AM, + ) + + with self.subTest( + 'Retrieves expected override dimensions for the longitude variable' + ): + self.assertEqual( + get_override_projected_dimensions(self.varinfo, self.longitude), + expected_override_dimensions_AM, + ) + + with self.subTest( + 'Retrieves expected override dimensions for the latitude variable' + ): + self.assertEqual( + get_override_projected_dimensions(self.varinfo, self.latitude), + expected_override_dimensions_AM, + ) + + with self.subTest( + 'Retrieves expected override dimensions science variable with a different grid' + ): + self.assertEqual( + get_override_projected_dimensions( + self.varinfo, '/Soil_Moisture_Retrieval_Data_PM/surface_flag_pm' + ), + expected_override_dimensions_PM, + ) + + def test_get_row_col_sizes_from_coordinate_datasets(self): + """Ensure that the correct row and column sizes are + returned for the requested coordinates + """ + expected_row_col_sizes = (5, 10) + lat_1d_array = np.array([1, 2, 3, 4]) + lon_1d_array = np.array([6, 7, 8, 9]) + lat_irregular_array = np.array([[1, 2, 3], [3, 4, 5]]) + lon_irregular_array = np.array([[6, 7], [8, 9], [10, 11]]) + with self.subTest('Retrieves the expected row col sizes from the coordinates'): + self.assertEqual( + get_row_col_sizes_from_coordinate_datasets(self.lat_arr, self.lon_arr), + expected_row_col_sizes, + ) + with self.subTest('Retrieves the expected row col sizes for the 1d array'): + self.assertEqual( + get_row_col_sizes_from_coordinate_datasets(lat_1d_array, lon_1d_array), + (4, 4), + ) + + with self.subTest( + 'Raises an exception when the lat and lon array shapes do not match' + ): + with self.assertRaises(IrregularCoordinateVariables) as context: + get_row_col_sizes_from_coordinate_datasets( + lat_irregular_array, lon_irregular_array + ) + self.assertEqual( + context.exception.message, + f'Longitude coordinate shape: "{lon_irregular_array.shape}"' + f'does not match the latitude coordinate shape: "{lat_irregular_array.shape}"', + ) + + 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_variables_with_anonymous_dims(self): + """Ensure that variables with no dimensions are + retrieved for the reqquested science variable + + """ + requested_science_variables = { + '/Soil_Moisture_Retrieval_Data_AM/surface_flag', + '/Soil_Moisture_Retrieval_Data_PM/surface_flag_pm', + } + + with self.subTest('Retrieves variables with no dimensions'): + variables_with_anonymous_dims = get_variables_with_anonymous_dims( + self.varinfo, requested_science_variables + ) + self.assertSetEqual( + variables_with_anonymous_dims, + requested_science_variables, + )