diff --git a/docs/iris/src/conf.py b/docs/iris/src/conf.py index 2833a01674..6cdfe634c4 100644 --- a/docs/iris/src/conf.py +++ b/docs/iris/src/conf.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2010 - 2017, Met Office +# (C) British Crown Copyright 2010 - 2018, Met Office # # This file is part of Iris. # diff --git a/docs/iris/src/whatsnew/contributions_2.2.0/bugfix_2018-Sep-19_gracefully-filling-warning-only-when-masked.txt b/docs/iris/src/whatsnew/contributions_2.2.0/bugfix_2018-Sep-19_gracefully-filling-warning-only-when-masked.txt new file mode 100644 index 0000000000..6b612ef109 --- /dev/null +++ b/docs/iris/src/whatsnew/contributions_2.2.0/bugfix_2018-Sep-19_gracefully-filling-warning-only-when-masked.txt @@ -0,0 +1 @@ +* Gracefully filling warnings are only issued when the co-ordinate or bound data is actually masked. diff --git a/lib/iris/analysis/_regrid.py b/lib/iris/analysis/_regrid.py index 71304a5dde..83561a2b94 100644 --- a/lib/iris/analysis/_regrid.py +++ b/lib/iris/analysis/_regrid.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2014 - 2017, Met Office +# (C) British Crown Copyright 2014 - 2018, Met Office # # This file is part of Iris. # diff --git a/lib/iris/fileformats/_pyke_rules/fc_rules_cf.krb b/lib/iris/fileformats/_pyke_rules/fc_rules_cf.krb index f301f0fc9b..5fc68e58c2 100644 --- a/lib/iris/fileformats/_pyke_rules/fc_rules_cf.krb +++ b/lib/iris/fileformats/_pyke_rules/fc_rules_cf.krb @@ -40,7 +40,7 @@ fc_default # # Context: -# This rule will trigger iff a grid_mapping() case specific fact +# This rule will trigger iff a grid_mapping() case specific fact # has been asserted that refers to a rotated pole. # # Purpose: @@ -120,7 +120,7 @@ fc_provides_grid_mapping_mercator # # Context: -# This rule will trigger iff a grid_mapping() case specific fact +# This rule will trigger iff a grid_mapping() case specific fact # has been asserted that refers to a stereographic. # # Purpose: @@ -199,10 +199,10 @@ fc_provides_grid_mapping_albers_equal_area # # Context: # This rule will trigger iff a coordinate() case specific fact -# has been asserted that refers to a CF latitude coordinate. +# has been asserted that refers to a CF latitude coordinate. # # Purpose: -# Assert that the CF latitude coordinate exists. +# Assert that the CF latitude coordinate exists. # fc_provides_coordinate_latitude foreach @@ -435,10 +435,10 @@ fc_build_auxiliary_coordinate_longitude_rotated # # Context: # This rule will trigger for each auxiliary_coordinate() case specific fact -# that is not a spatio-temporal related auxiliary coordinate. +# that is not a spatio-temporal related auxiliary coordinate. # # Purpose: -# Add the auxiliary coordinate to the cube. +# Add the auxiliary coordinate to the cube. # fc_build_auxiliary_coordinate foreach @@ -457,7 +457,7 @@ fc_build_auxiliary_coordinate # This rule will trigger for each cell_measure case specific fact. # # Purpose: -# Add the cell measures attribute to the cube. +# Add the cell measures attribute to the cube. # fc_build_cell_measure foreach @@ -549,7 +549,7 @@ fc_build_coordinate_longitude_rotated python build_dimension_coordinate(engine, cf_coord_var, coord_name=CF_VALUE_STD_NAME_GRID_LON, coord_system=engine.provides['coordinate_system']) - python engine.rule_triggered.add(rule.name) + python engine.rule_triggered.add(rule.name) # @@ -597,7 +597,7 @@ fc_build_coordinate_longitude_nocs coord_system=None) python engine.rule_triggered.add(rule.name) - + # # Context: # This rule will trigger iff a projection_x_coordinate coordinate exists and @@ -917,8 +917,8 @@ fc_attribute_ukmo__process_flags python attr_value = engine.cf_var.ukmo__process_flags python engine.cube.attributes['ukmo__process_flags'] = tuple([x.replace("_", " ") for x in attr_value.split(" ")]) python engine.rule_triggered.add(rule.name) - - + + # # Context: # This rule will trigger iff a formula term that refers to a @@ -1076,8 +1076,8 @@ fc_extras import iris.std_names import iris.util from iris._lazy_data import as_lazy_data - - + + # # UD Units Constants (based on Unidata udunits.dat definition file) # @@ -1087,7 +1087,7 @@ fc_extras UD_UNITS_LON = ['degrees_east', 'degree_east', 'degree_e', 'degrees_e', 'degreee', 'degreese', 'degrees', 'degrees east', 'degree east', 'degree e', 'degrees e'] - + # # CF Dimensionless Vertical Coordinates # @@ -1119,7 +1119,7 @@ fc_extras CF_GRID_MAPPING_STEREO = 'stereographic' CF_GRID_MAPPING_TRANSVERSE = 'transverse_mercator' CF_GRID_MAPPING_VERTICAL = 'vertical_perspective' - + # # CF Attribute Names. # @@ -1149,7 +1149,7 @@ fc_extras CF_ATTR_LONG_NAME = 'long_name' CF_ATTR_UNITS = 'units' CF_ATTR_CELL_METHODS = 'cell_methods' - + # # CF Attribute Value Constants. # @@ -1158,11 +1158,11 @@ fc_extras CF_VALUE_AXIS_Y = 'y' CF_VALUE_AXIS_T = 't' CF_VALUE_AXIS_Z = 'z' - - + + # Attribute - positive. CF_VALUE_POSITIVE = ['down', 'up'] - + # Attribute - standard_name. CF_VALUE_STD_NAME_LAT = 'latitude' CF_VALUE_STD_NAME_LON = 'longitude' @@ -1213,7 +1213,7 @@ fc_extras msg = msg.replace('variable', 'variable {!r}'.format(name)) warnings.warn(message=msg, category=UnknownCellMethodWarning) - # Set the cube global attributes. + # Set the cube global attributes. for attr_name, attr_value in six.iteritems(cf_var.cf_group.global_attributes): try: if six.PY2 and isinstance(attr_value, six.text_type): @@ -1242,7 +1242,7 @@ fc_extras # Check for a default spherical earth. if major is None and minor is None and inverse_flattening is None: - major = getattr(cf_grid_var, CF_ATTR_GRID_EARTH_RADIUS, None) + major = getattr(cf_grid_var, CF_ATTR_GRID_EARTH_RADIUS, None) return major, minor, inverse_flattening @@ -1344,7 +1344,7 @@ fc_extras inverse_flattening is not None: ellipsoid = iris.coord_systems.GeogCS(major, minor, inverse_flattening) - + cs = iris.coord_systems.LambertConformal( latitude_of_projection_origin, longitude_of_central_meridian, false_easting, false_northing, standard_parallel, @@ -1401,7 +1401,7 @@ fc_extras # values for false_easting, false_northing, # scale_factor_at_projection_origin and standard_parallel. These are # checked elsewhere. - + ellipsoid = None if major is not None or minor is not None or \ inverse_flattening is not None: @@ -1621,7 +1621,7 @@ fc_extras attr_units = get_attr_units(cf_coord_var, attributes) points_data = cf_coord_var[:] # Gracefully fill points masked array. - if ma.isMaskedArray(points_data): + if ma.is_masked(points_data): points_data = ma.filled(points_data) msg = 'Gracefully filling {!r} dimension coordinate masked points' warnings.warn(msg.format(str(cf_coord_var.cf_name))) @@ -1631,7 +1631,7 @@ fc_extras if cf_bounds_var is not None: bounds_data = cf_bounds_var[:] # Gracefully fill bounds masked array. - if ma.isMaskedArray(bounds_data): + if ma.is_masked(bounds_data): bounds_data = ma.filled(bounds_data) msg = 'Gracefully filling {!r} dimension coordinate masked bounds' warnings.warn(msg.format(str(cf_coord_var.cf_name))) @@ -1696,7 +1696,7 @@ fc_extras else: # Scalar coords are placed in the aux_coords container. cube.add_aux_coord(coord, data_dims) - + # Update the coordinate to CF-netCDF variable mapping. engine.provides['coordinates'].append((coord, cf_coord_var.cf_name)) @@ -1739,7 +1739,7 @@ fc_extras # and the coordinate being built. common_dims = [dim for dim in cf_coord_var.dimensions if dim in cf_var.dimensions] - data_dims = None + data_dims = None if common_dims: # Calculate the offset of each common dimension. data_dims = [cf_var.dimensions.index(dim) for dim in common_dims] @@ -1763,7 +1763,7 @@ fc_extras # Update the coordinate to CF-netCDF variable mapping. engine.provides['coordinates'].append((coord, cf_coord_var.cf_name)) - + ################################################################################ def build_cell_measures(engine, cf_cm_attr, coord_name=None): """Create a CellMeasure instance and add it to the cube.""" @@ -1780,19 +1780,19 @@ fc_extras # and the coordinate being built. common_dims = [dim for dim in cf_cm_attr.dimensions if dim in cf_var.dimensions] - data_dims = None + data_dims = None if common_dims: # Calculate the offset of each common dimension. data_dims = [cf_var.dimensions.index(dim) for dim in common_dims] # Determine the standard_name, long_name and var_name standard_name, long_name, var_name = get_names(cf_cm_attr, coord_name, attributes) - + # Obtain the cf_measure. measure = cf_cm_attr.cf_measure - + # Create the CellMeasure - cell_measure = iris.coords.CellMeasure(data, + cell_measure = iris.coords.CellMeasure(data, standard_name=standard_name, long_name=long_name, var_name=var_name, @@ -1802,17 +1802,17 @@ fc_extras # Add it to the cube cube.add_cell_measure(cell_measure, data_dims) - + ################################################################################ def _is_lat_lon(cf_var, ud_units, std_name, std_name_grid, axis_name, prefixes): """ Determine whether the CF coordinate variable is a latitude/longitude variable. - + Ref: [CF] Section 4.1 Latitude Coordinate. [CF] Section 4.2 Longitude Coordinate. - + """ is_valid = False attr_units = getattr(cf_var, CF_ATTR_UNITS, None) @@ -1854,7 +1854,7 @@ fc_extras def is_latitude(engine, cf_name): """Determine whether the CF coordinate variable is a latitude variable.""" cf_var = engine.cf_var.cf_group[cf_name] - return _is_lat_lon(cf_var, UD_UNITS_LAT, CF_VALUE_STD_NAME_LAT, + return _is_lat_lon(cf_var, UD_UNITS_LAT, CF_VALUE_STD_NAME_LAT, CF_VALUE_STD_NAME_GRID_LAT, CF_VALUE_AXIS_Y, ['lat', 'rlat']) @@ -1910,7 +1910,7 @@ fc_extras is_time_reference = cf_units.Unit(attr_units or 1).is_time_reference() except ValueError: is_time_reference = False - + return is_time_reference and (attr_std_name=='time' or attr_axis.lower()==CF_VALUE_AXIS_T) @@ -1978,7 +1978,7 @@ fc_extras def has_supported_mercator_parameters(engine, cf_name): """Determine whether the CF grid mapping variable has the supported values for the parameters of the Mercator projection.""" - + is_valid = True cf_grid_var = engine.cf_var.cf_group[cf_name] @@ -2018,8 +2018,8 @@ fc_extras ################################################################################ def has_supported_stereographic_parameters(engine, cf_name): """Determine whether the CF grid mapping variable has a value of 1.0 - for the scale_factor_at_projection_origin attribute.""" - + for the scale_factor_at_projection_origin attribute.""" + is_valid = True cf_grid_var = engine.cf_var.cf_group[cf_name] @@ -2102,6 +2102,6 @@ fc_extras if len(d[CM_NAME]) != len(comment) and len(comment) == 1: comment = comment*len(d[CM_NAME]) d[CM_INTERVAL] = tuple(interval) - d[CM_COMMENT] = tuple(comment) + d[CM_COMMENT] = tuple(comment) cell_methods.append(iris.coords.CellMethod(d[CM_METHOD], coords=d[CM_NAME], intervals=d[CM_INTERVAL], comments=d[CM_COMMENT])) return tuple(cell_methods) diff --git a/lib/iris/tests/integration/test_regridding.py b/lib/iris/tests/integration/test_regridding.py index 47d155f3f2..80878c21b5 100644 --- a/lib/iris/tests/integration/test_regridding.py +++ b/lib/iris/tests/integration/test_regridding.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2013 - 2017, Met Office +# (C) British Crown Copyright 2013 - 2018, Met Office # # This file is part of Iris. # diff --git a/lib/iris/tests/test_coordsystem.py b/lib/iris/tests/test_coordsystem.py index 6def1a3123..5aef363533 100644 --- a/lib/iris/tests/test_coordsystem.py +++ b/lib/iris/tests/test_coordsystem.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2010 - 2017, Met Office +# (C) British Crown Copyright 2010 - 2018, Met Office # # This file is part of Iris. # diff --git a/lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py b/lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py index 41b6ca5ff0..603547b707 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py +++ b/lib/iris/tests/unit/fileformats/netcdf/test__load_cube.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2014 - 2017, Met Office +# (C) British Crown Copyright 2014 - 2018, Met Office # # This file is part of Iris. # diff --git a/lib/iris/tests/unit/fileformats/pp/test_save.py b/lib/iris/tests/unit/fileformats/pp/test_save.py index 081e01fcf9..361c01f936 100644 --- a/lib/iris/tests/unit/fileformats/pp/test_save.py +++ b/lib/iris/tests/unit/fileformats/pp/test_save.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2014 - 2017, Met Office +# (C) British Crown Copyright 2014 - 2018, Met Office # # This file is part of Iris. # diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_dimension_coordinate.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_dimension_coordinate.py index c645f984cc..38239ea9a0 100644 --- a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_dimension_coordinate.py +++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_dimension_coordinate.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2014 - 2015, Met Office +# (C) British Crown Copyright 2014 - 2018, Met Office # # This file is part of Iris. # @@ -112,6 +112,84 @@ def test_dim_coord_construction(self): self.engine.cube.add_dim_coord.assert_called_with( expected_coord, [0]) + def test_dim_coord_construction_masked_array(self): + self._set_cf_coord_var(np.ma.array( + np.arange(6), + mask=[True, False, False, False, False, False], + fill_value=-999, + )) + + expected_coord = DimCoord( + np.array([-999, 1, 2, 3, 4, 5]), + long_name=self.cf_coord_var.long_name, + var_name=self.cf_coord_var.cf_name, + units=self.cf_coord_var.units, + bounds=self.bounds) + + with warnings.catch_warnings(record=True) as w: + # Asserts must lie within context manager because of deferred + # loading. + with self.deferred_load_patch, self.get_cf_bounds_var_patch: + build_dimension_coordinate(self.engine, self.cf_coord_var) + + # Test that expected coord is built and added to cube. + self.engine.cube.add_dim_coord.assert_called_with( + expected_coord, [0]) + + # Assert warning is raised + assert len(w) == 1 + assert 'Gracefully filling' in w[0].message.args[0] + + def test_dim_coord_construction_masked_array_mask_does_nothing(self): + self._set_cf_coord_var(np.ma.array( + np.arange(6), + mask=False, + )) + + expected_coord = DimCoord( + self.cf_coord_var[:], + long_name=self.cf_coord_var.long_name, + var_name=self.cf_coord_var.cf_name, + units=self.cf_coord_var.units, + bounds=self.bounds) + + with warnings.catch_warnings(record=True) as w: + # Asserts must lie within context manager because of deferred + # loading. + with self.deferred_load_patch, self.get_cf_bounds_var_patch: + build_dimension_coordinate(self.engine, self.cf_coord_var) + + # Test that expected coord is built and added to cube. + self.engine.cube.add_dim_coord.assert_called_with( + expected_coord, [0]) + + # Assert no warning is raised + assert len(w) == 0 + + def test_dim_coord_construction_masked_bounds_mask_does_nothing(self): + self.bounds = np.ma.array(np.arange(12).reshape(6, 2), mask=False) + self._set_cf_coord_var(np.arange(6)) + + expected_coord = DimCoord( + self.cf_coord_var[:], + long_name=self.cf_coord_var.long_name, + var_name=self.cf_coord_var.cf_name, + units=self.cf_coord_var.units, + bounds=self.bounds) + + with warnings.catch_warnings(record=True) as w: + # Asserts must lie within context manager because of deferred + # loading. + with self.deferred_load_patch, self.get_cf_bounds_var_patch: + build_dimension_coordinate(self.engine, self.cf_coord_var) + + # Test that expected coord is built and added to cube. + self.engine.cube.add_dim_coord.assert_called_with( + expected_coord, [0]) + + # Assert no warning is raised + assert len(w) == 0 + def test_aux_coord_construction(self): # Use non monotonically increasing coordinates to force aux coord # construction.