From 12a3849aac1c6cf59f043677f5556bc2e5dcbb11 Mon Sep 17 00:00:00 2001 From: RosalynHatcher Date: Mon, 26 Feb 2018 12:48:48 +0000 Subject: [PATCH] Addition checks for grid_mapping variables for CF-1.7 Ticket #31 --- src/cfchecker/cfchecks.py | 161 ++++++++++++++++++++++++++++++++-- test_files/CF_1_7.check | 71 ++++++++++++++- test_files/CF_1_7.nc.gz | Bin 2807 -> 1545 bytes test_files/example_5.10.check | 51 +++++++++++ test_files/example_5.10.nc.gz | Bin 0 -> 800575 bytes test_files/tests.sh | 5 +- 6 files changed, 273 insertions(+), 15 deletions(-) create mode 100644 test_files/example_5.10.check create mode 100644 test_files/example_5.10.nc.gz diff --git a/src/cfchecker/cfchecks.py b/src/cfchecker/cfchecks.py index 489388e..515f964 100644 --- a/src/cfchecker/cfchecks.py +++ b/src/cfchecker/cfchecks.py @@ -351,6 +351,7 @@ def checker(self, file): # Set up dictionary of all valid attributes, their type and use self.setUpAttributeList() + self.validGridMappingAttributes() # Set up dictionary of standard_names and their assoc. units parser = make_parser() @@ -1065,19 +1066,120 @@ def getCoordinateDataVars(self): #------------------------------------------ if hasattr(self.f.variables[var], 'grid_mapping'): grid_mapping = self.f.variables[var].grid_mapping - # Check syntax of grid_mapping attribute: a string whose value is a single variable name. - if not re.search("^[a-zA-Z0-9_]*$",grid_mapping): - self._add_error("%s - Invalid syntax for 'grid_mapping' attribute" % var, var, code="5.6") - else: - if grid_mapping in variables: - gridMappingVars.append(grid_mapping) + + (grid_mapping_vars, coord_vars) = self.chkGridMappingAttribute(var, grid_mapping) + + for gmv in grid_mapping_vars: + if gmv in variables: + gridMappingVars.append(gmv) else: - self._add_error("grid_mapping attribute referencing non-existent variable %s" % grid_mapping, - var) + self._add_error("grid_mapping attribute referencing non-existent variable %s" % gmv, + var, code="5.6") + + for cv in coord_vars: + # cv must be the name of a coordinate variable or auxiliary coordinate variable + if cv not in self.f.variables[var].dimensions and cv not in coordinates: + self._add_error("%s must be the name of a coordinate variable or auxiliary coordinate variable of %s" % (cv,var), + var, code="5.6") + if cv not in allVariables: + self._add_error("grid_mapping attribute referencing non-existent coordinate variable %s" % cv, + var, code="5.6") return (coordVars, auxCoordVars, boundaryVars, climatologyVars, gridMappingVars) + #------------------ + def subst(self, s): + #------------------ + "substitute tokens for WORD and SEP (space or end of string)" + return s.replace('WORD', r'[A-Za-z0-9_]+').replace('SEP', r'(\s+|$)') + + #-------------------------------------------------------- + def chkGridMappingAttribute(self, varName, grid_mapping): + #-------------------------------------------------------- + """Validate syntax of grid_mapping attribute""" + + grid_mapping_vars=[] + coord_vars=[] + + if self.version < vn1_7: + # Syntax: a string whose value is a single variable name + pat_sole = self.subst('(?PWORD)$') + m = re.match(pat_sole, grid_mapping) + + else: + # Syntax: a string whose value is a single variable name or of the form: + # grid_mapping_var: coord_var [coord_var ...] [grid_mapping_var: coord_var [coord_var ...]] + + pat_coord = self.subst('(?PWORD)SEP') + pat_coord_list = '({})+'.format(pat_coord) + + pat_mapping = self.subst('(?PWORD):SEP(?P{})'.format(pat_coord_list)) + pat_mapping_list = '({})+'.format(pat_mapping) + + pat_all = self.subst('((?PWORD)|(?P{}))$'.format(pat_mapping_list)) + + m = re.match(pat_all, grid_mapping) + + if not m: + self._add_error("%s - Invalid syntax for 'grid_mapping' attribute" % varName, varName, code="5.6") + return ([], []) + + # Parse grid_mapping attribute to obtain a list of grid_mapping_vars and a list of coord_vars + sole_mapping = m.group('sole_mapping') + if sole_mapping: + # Contains only a single variable name + grid_mapping_vars.append(sole_mapping) + + else: + # Complex form, split into lists of grid_mapping_vars and coord_vars + mapping_list = m.group('mapping_list') + for mapping in re.finditer(pat_mapping, mapping_list): + mapping_name = mapping.group('mapping_name') + coord_list = mapping.group('coord_list') + + grid_mapping_vars.append(mapping_name) + for coord in re.finditer(pat_coord, coord_list): + coord_vars.append(coord.group('coord')) + + return (map(str,grid_mapping_vars), map(str,coord_vars)) + + #------------------------------------ + def validGridMappingAttributes(self): + #------------------------------------ + """Setup dictionary of valid grid mapping attributes and their types""" + + self.grid_mapping_attrs=dict([('azimuth_of_central_line', 'N'), + ('crs_wkt', 'S'), + ('earth_radius', 'N'), + ('false_easting', 'N'), + ('false_northing', 'N'), + ('geographic_crs_name', 'S'), + ('geoid_name', 'S'), + ('geopotential_datum_name', 'S'), + ('grid_mapping_name', 'S'), + ('grid_north_pole_latitude', 'N'), + ('grid_north_pole_longitude', 'N'), + ('horizontal_datum_name', 'S'), + ('inverse_flattening', 'N'), + ('latitude_of_projection_origin', 'N'), + ('longitude_of_central_meridian', 'N'), + ('longitude_of_prime_meridian', 'N'), + ('longitude_of_projection_origin', 'N'), + ('north_pole_grid_longitude', 'N'), + ('perspective_point_height', 'N'), + ('prime_meridian_name', 'S'), + ('projected_crs_name', 'S'), + ('reference_ellipsoid_name', 'S'), + ('scale_factor_at_central_meridian', 'N'), + ('scale_factor_at_projection_origin', 'N'), + ('semi_major_axis', 'N'), + ('semi_minor_axis', 'N'), + ('standard_parallel', 'N'), + ('straight_vertical_longitude_from_pole', 'N'), + ('towgs84', 'N')]) + return + #------------------------------------- def chkGridMappingVar(self, varName): #------------------------------------- @@ -1097,6 +1199,10 @@ def chkGridMappingVar(self, varName): if self.version >= vn1_4: # Extra grid_mapping_names at vn1.4 validNames[len(validNames):] = ['lambert_cylindrical_equal_area','mercator','orthographic'] + + if self.version >= vn1_7: + # Extra grid_mapping_names at vn1.7 + validNames[len(validNames):] = ['geostationary', 'oblique_mercator', 'sinusoidal'] if var.grid_mapping_name not in validNames: self._add_error("Invalid grid_mapping_name: %s" % var.grid_mapping_name, @@ -1109,6 +1215,45 @@ def chkGridMappingVar(self, varName): self._add_warn("A grid mapping variable should have 0 dimensions", varName, code="5.6") + for attribute in map(str, var.ncattrs()): + + # Check type of attribute matches that specified in Appendix F: Table 1 + attr_type = type(var.getncattr(attribute)) + + if isinstance(var.getncattr(attribute), basestring): + attr_type='S' + + elif (numpy.issubdtype(attr_type, numpy.int) or + numpy.issubdtype(attr_type, numpy.float) or + attr_type == numpy.ndarray): + attr_type='N' + + else: + self._add_info("Unknown Type for attribute: %s %s" % (attribute, attr_type)) + continue + + if (attribute in self.grid_mapping_attrs.keys() and + attr_type != self.grid_mapping_attrs[attribute]): + self._add_error("Attribute %s of incorrect data type (Appendix F)" % attribute, + varName, code="5.6") + + if self.version >= vn1_7: + if hasattr(var, 'crs_wkt'): + msg = "CF checker currently does not verify the syntax of the crs_wkt attribute " \ + "which must conform to the CRS WKT specification" + self._add_info(msg, varName, code="5.6") + + # If any of these attributes are present then they all must be + l=['reference_ellipsoid_name', 'prime_meridian_name', 'horizontal_datum_name', 'geographic_crs_name'] + if any(hasattr(var, x) for x in l) and not all(hasattr(var, x) for x in l): + msg = "reference_ellipsoid_name, prime_meridian_name, horizontal_datum_name " \ + "and geographic_crs_name must all be definied if any one is defined" + self._add_error(msg, varName, code="5.6") + + if hasattr(var, 'projected_crs_name') and not hasattr(var, 'geographic_crs_name'): + self._add_error("projected_crs_name is defined therefore geographic_crs_name must be also", + varName, code="5.6") + #------------------------ def setUpFormulas(self): #------------------------ diff --git a/test_files/CF_1_7.check b/test_files/CF_1_7.check index 22487d5..9a096de 100644 --- a/test_files/CF_1_7.check +++ b/test_files/CF_1_7.check @@ -11,7 +11,6 @@ ERROR: (2.6.3): Variable external_var2 named as an external variable must not be ------------------ Checking variable: lat ------------------ -ERROR: (5): co-ordinate variable not monotonic ------------------ Checking variable: lon @@ -65,6 +64,70 @@ Checking variable: arv4 ERROR: (2.5.1): actual_range attribute must be of same type as variable arv4 ERROR: (2.5.1): actual_range values must be greater than or equal to 15.0 (valid_min) -ERRORS detected: 14 -WARNINGS given: 0 -INFORMATION messages: 0 +------------------ +Checking variable: current_speed_qc +------------------ +WARN: (3.3): Use of standard_name modifier status_flag is deprecated + +------------------ +Checking variable: current_speed_qc2 +------------------ +WARN: (3.3): Use of standard_name modifier number_of_observations is deprecated + +------------------ +Checking variable: n_heat_transport +------------------ + +------------------ +Checking variable: geo_region +------------------ +ERROR: (3.3): Invalid region name: dummy_ocean + +------------------ +Checking variable: lev +------------------ +ERROR: (4.3.3): Standard name of variable PS inconsistent with that of lev +ERROR: (4.3.3): PTOP is not declared as a variable +ERROR: (5): co-ordinate variable not monotonic + +------------------ +Checking variable: PS +------------------ + +------------------ +Checking variable: sigma +------------------ +ERROR: (4.3.3): Formula term dummy not present in formula for ocean_sigma_coordinate +ERROR: (4.3.3): Standard names of formula_terms variables are inconsistent/invalid +ERROR: (5): co-ordinate variable not monotonic + +------------------ +Checking variable: var2 +------------------ +INFO: (3.1): No units attribute set. Please consider adding a units attribute for completeness. + +------------------ +Checking variable: var3 +------------------ +INFO: (3.1): No units attribute set. Please consider adding a units attribute for completeness. + +------------------ +Checking variable: sigma2 +------------------ +WARN: (3.1): units attribute should be present +ERROR: (4.3.3): computed_standard_name attribute is only allowed on a coordinate variable which has a formula_terms attribute +ERROR: (5): co-ordinate variable not monotonic + +------------------ +Checking variable: temp +------------------ + +------------------ +Checking variable: crs +------------------ +ERROR: (5.6): Attribute longitude_of_prime_meridian of incorrect data type (Appendix F) +ERROR: (5.6): reference_ellipsoid_name, prime_meridian_name, horizontal_datum_name and geographic_crs_name must all be definied if any one is defined + +ERRORS detected: 24 +WARNINGS given: 3 +INFORMATION messages: 2 diff --git a/test_files/CF_1_7.nc.gz b/test_files/CF_1_7.nc.gz index 4c0a5f105f61c9e56e87364b23b2b98f9c39f1de..3285767b320fd1c4effd6fd3970776b2edd75d6b 100644 GIT binary patch literal 1545 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 $outdir/$file.out 2>&1 - elif [[ $file == "CF_1_7.nc" || $file = "example_6.2.nc" ]] + elif [[ $file == "CF_1_7.nc" || $file == "example_6.2.nc" || $file == "example_5.10.nc" ]] then - # CF-1.7 + # Run checker using the CF version specified in the conventions attribute of the file $cfchecker -s $std_name_table -v auto $file > $outdir/$file.out 2>&1 else # Run the checker on the file