diff --git a/compliance_checker/cfutil.py b/compliance_checker/cfutil.py index a9dbe935..bfb6adfc 100644 --- a/compliance_checker/cfutil.py +++ b/compliance_checker/cfutil.py @@ -194,6 +194,9 @@ def is_geophysical(ds, variable): if variable in get_auxiliary_coordinate_variables(ds): return False + if variable in get_forecast_metadata_variables(ds): + return False + # Is it dimensionless and unitless? if len(ncvar.shape) == 0 and unitless: return False @@ -296,6 +299,26 @@ def get_auxiliary_coordinate_variables(ds): return ret_val +def get_forecast_metadata_variables(ds): + ''' + Returns a list of variables that represent forecast reference time + metadata. + + :param netCDF4.Dataset ds: An open netCDF4 Dataset. + :rtype: list + ''' + forecast_metadata_standard_names = { + 'forecast_period', + 'forecast_reference_time', + } + forecast_metadata_variables = [] + for varname in ds.variables: + standard_name = getattr(ds.variables[varname], 'standard_name', None) + if standard_name in forecast_metadata_standard_names: + forecast_metadata_variables.append(varname) + return forecast_metadata_variables + + def get_cell_boundary_map(ds): ''' Returns a dictionary mapping a variable to its boundary variable. The diff --git a/compliance_checker/tests/data/forecast_reference.cdl b/compliance_checker/tests/data/forecast_reference.cdl new file mode 100644 index 00000000..b12eb573 --- /dev/null +++ b/compliance_checker/tests/data/forecast_reference.cdl @@ -0,0 +1,32 @@ +netcdf forecast_reference.cdl { +dimensions: + time = 2 ; + lat = 4 ; + lon = 4 ; +variables: + float time(time) ; + time:units = "seconds since 1970-01-01" ; + time:standard_name = "time" ; + time:calendar = "gregorian" ; + time:axis = "T" ; + float lat(lat) ; + lat:units = "degrees_north" ; + lat:standard_name = "latitude" ; + lat:axis = "Y" ; + float lon(lon) ; + lon:units = "degrees_east" ; + lon:standard_name = "longitude" ; + lon:axis = "X" ; + float air_temp(time, lon, lat) ; + air_temp:units = "deg_C" ; + air_temp:standard_name = "air_temperature"; + float forecast_reference_time(time) ; + forecast_reference_time:units = "seconds since 1970-01-01" ; + forecast_reference_time:standard_name = "forecast_reference_time" ; + float forecast_hour(time) ; + forecast_hour:units = "hours" ; + forecast_hour:standard_name = "forecast_period" ; + + :featureType = "grid" ; + +} diff --git a/compliance_checker/tests/resources.py b/compliance_checker/tests/resources.py index d125ff64..d305ecb3 100644 --- a/compliance_checker/tests/resources.py +++ b/compliance_checker/tests/resources.py @@ -48,6 +48,7 @@ def generate_dataset(cdl_path, nc_path): 'dimension_order' : get_filename('tests/data/dimension_order.cdl'), 'example-grid' : get_filename('tests/data/example-grid.cdl'), 'featureType' : get_filename('tests/data/example-grid.cdl'), + 'forecast_reference' : get_filename('tests/data/forecast_reference.cdl'), 'fvcom' : get_filename('tests/data/examples/fvcom.cdl'), 'ghrsst' : get_filename('tests/data/20160919092000-ABOM-L3S_GHRSST-SSTfnd-AVHRR_D-1d_dn_truncate.cdl'), 'glcfs' : get_filename('tests/data/examples/glcfs.cdl'), diff --git a/compliance_checker/tests/test_feature_detection.py b/compliance_checker/tests/test_feature_detection.py index cbba1b9d..3426e30d 100644 --- a/compliance_checker/tests/test_feature_detection.py +++ b/compliance_checker/tests/test_feature_detection.py @@ -226,6 +226,20 @@ def test_auxiliary_coordinates(self): aux_coord_vards = util.get_auxiliary_coordinate_variables(nc) assert set(['lat', 'lon']) == set(aux_coord_vards) + def test_forecast_reference_metadata(self): + ''' + Tests variables used for forecast reference metadata to ensure they are + not misclassified as geophysical variables. + ''' + with Dataset(resources.STATIC_FILES['forecast_reference']) as nc: + self.assertFalse(util.is_geophysical(nc, 'forecast_reference_time')) + self.assertFalse(util.is_geophysical(nc, 'forecast_hour')) + self.assertTrue(util.is_geophysical(nc, 'air_temp')) + self.assertFalse(util.is_geophysical(nc, 'time')) + + assert len(util.get_coordinate_variables(nc)) == 3 + assert len(util.get_geophysical_variables(nc)) == 1 + def test_rotated_pole_grid(self): with Dataset(resources.STATIC_FILES['rotated_pole_grid']) as nc: latitudes = util.get_latitude_variables(nc)