From af187e1effccc3be5082496278090694cebe0161 Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Tue, 15 Feb 2022 14:11:13 +0000 Subject: [PATCH 1/9] Changes to coord_systems --- lib/iris/coord_systems.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/iris/coord_systems.py b/lib/iris/coord_systems.py index 311ed35f44..78080128f9 100644 --- a/lib/iris/coord_systems.py +++ b/lib/iris/coord_systems.py @@ -1083,6 +1083,7 @@ def __init__( longitude_of_projection_origin=None, ellipsoid=None, standard_parallel=None, + scale_factor_at_projection_origin=None, false_easting=None, false_northing=None, ): @@ -1100,12 +1101,18 @@ def __init__( * standard_parallel: The latitude where the scale is 1. Defaults to 0.0 . + * scale_factor_at_projection_origin: + Scale factor at natural origin. Defaults to unused. + * false_easting: X offset from the planar origin in metres. Defaults to 0.0. * false_northing: Y offset from the planar origin in metres. Defaults to 0.0. + Note: Only one of ``latitude_true_scale`` and + ``scale_factor_at_projection_origin`` should be included. + """ #: True longitude of planar origin in degrees. self.longitude_of_projection_origin = _arg_default( @@ -1115,8 +1122,20 @@ def __init__( #: Ellipsoid definition (:class:`GeogCS` or None). self.ellipsoid = ellipsoid - #: The latitude where the scale is 1. - self.standard_parallel = _arg_default(standard_parallel, 0) + if scale_factor_at_projection_origin is None: + #: The latitude where the scale is 1. + self.standard_parallel = _arg_default(standard_parallel, 0) + else: + if standard_parallel is None: + # The scale factor at the origin of the projection + self.scale_factor_at_projection_origin = _arg_default( + scale_factor_at_projection_origin, 0 + ) + else: + raise ValueError( + "It does not make sense to provide both " + '"scale_factor" and "latitude_true_scale". ' + ) #: X offset from the planar origin in metres. self.false_easting = _arg_default(false_easting, 0) @@ -1130,6 +1149,8 @@ def __repr__(self): "{self.longitude_of_projection_origin!r}, " "ellipsoid={self.ellipsoid!r}, " "standard_parallel={self.standard_parallel!r}, " + "scale_factor_at_projection_origin=" + "{self.scale_factor_at_projection_origin!r}, " "false_easting={self.false_easting!r}, " "false_northing={self.false_northing!r})" ) @@ -1142,6 +1163,7 @@ def as_cartopy_crs(self): central_longitude=self.longitude_of_projection_origin, globe=globe, latitude_true_scale=self.standard_parallel, + scale_factor=self.scale_factor_at_projection_origin, false_easting=self.false_easting, false_northing=self.false_northing, ) From 81c1ecf3d01e799ff72cd67eaef1d5f4d421f3ef Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Mon, 21 Feb 2022 13:20:40 +0000 Subject: [PATCH 2/9] Finish feature --- lib/iris/coord_systems.py | 5 +++-- lib/iris/fileformats/_nc_load_rules/helpers.py | 15 ++++++++++----- lib/iris/fileformats/netcdf.py | 7 ++++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/iris/coord_systems.py b/lib/iris/coord_systems.py index 78080128f9..333ce36543 100644 --- a/lib/iris/coord_systems.py +++ b/lib/iris/coord_systems.py @@ -1110,7 +1110,7 @@ def __init__( * false_northing: Y offset from the planar origin in metres. Defaults to 0.0. - Note: Only one of ``latitude_true_scale`` and + Note: Only one of ``standard_parallel`` and ``scale_factor_at_projection_origin`` should be included. """ @@ -1134,7 +1134,8 @@ def __init__( else: raise ValueError( "It does not make sense to provide both " - '"scale_factor" and "latitude_true_scale". ' + '"scale_factor_at_projection_origin" and ' + '"standard_parallel".' ) #: X offset from the planar origin in metres. diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index 198daeceea..954250b4a2 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -445,8 +445,9 @@ def build_mercator_coordinate_system(engine, cf_grid_var): ) false_easting = getattr(cf_grid_var, CF_ATTR_GRID_FALSE_EASTING, None) false_northing = getattr(cf_grid_var, CF_ATTR_GRID_FALSE_NORTHING, None) - # Iris currently only supports Mercator projections with specific - # scale_factor_at_projection_origin. This is checked elsewhere. + scale_factor_at_projection_origin = getattr( + cf_grid_var, CF_ATTR_GRID_SCALE_FACTOR_AT_PROJ_ORIGIN, None + ) ellipsoid = None if ( @@ -460,6 +461,7 @@ def build_mercator_coordinate_system(engine, cf_grid_var): longitude_of_projection_origin, ellipsoid=ellipsoid, standard_parallel=standard_parallel, + scale_factor_at_projection_origin=scale_factor_at_projection_origin, false_easting=false_easting, false_northing=false_northing, ) @@ -1251,17 +1253,20 @@ def has_supported_mercator_parameters(engine, cf_name): is_valid = True cf_grid_var = engine.cf_var.cf_group[cf_name] + standard_parallel = getattr( + cf_grid_var, CF_ATTR_GRID_STANDARD_PARALLEL, None + ) scale_factor_at_projection_origin = getattr( cf_grid_var, CF_ATTR_GRID_SCALE_FACTOR_AT_PROJ_ORIGIN, None ) if ( scale_factor_at_projection_origin is not None - and scale_factor_at_projection_origin != 1 + and standard_parallel is not None ): warnings.warn( - "Scale factors other than 1.0 not yet supported for " - "Mercator projections" + "It does not make sense to provide both " + '"scale_factor_at_projection_origin" and "standard_parallel".' ) is_valid = False diff --git a/lib/iris/fileformats/netcdf.py b/lib/iris/fileformats/netcdf.py index 72ffe8ddb5..3ee430084c 100644 --- a/lib/iris/fileformats/netcdf.py +++ b/lib/iris/fileformats/netcdf.py @@ -2563,7 +2563,12 @@ def add_ellipsoid(ellipsoid): ) cf_var_grid.false_easting = cs.false_easting cf_var_grid.false_northing = cs.false_northing - cf_var_grid.scale_factor_at_projection_origin = 1.0 + if cs.scale_factor_at_projection_origin is not None: + cf_var_grid.scale_factor_at_projection_origin = ( + cs.scale_factor_at_projection_origin + ) + if cs.standard_parallel is not None: + cf_var_grid.standard_parallel = cs.standard_parallel # lcc elif isinstance(cs, iris.coord_systems.LambertConformal): From d7c1ce8561a091d0608b44d2d32d8ba52eff11ba Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Mon, 21 Feb 2022 16:55:22 +0000 Subject: [PATCH 3/9] Define both standard_parallel and scale_factor... but leave one None --- lib/iris/coord_systems.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/iris/coord_systems.py b/lib/iris/coord_systems.py index 333ce36543..510aafcb48 100644 --- a/lib/iris/coord_systems.py +++ b/lib/iris/coord_systems.py @@ -1122,12 +1122,15 @@ def __init__( #: Ellipsoid definition (:class:`GeogCS` or None). self.ellipsoid = ellipsoid + # Initialise to None, then set based on arguments + #: The latitude where the scale is 1. + self.standard_parallel = None + # The scale factor at the origin of the projection + self.scale_factor_at_projection_origin = None if scale_factor_at_projection_origin is None: - #: The latitude where the scale is 1. self.standard_parallel = _arg_default(standard_parallel, 0) else: if standard_parallel is None: - # The scale factor at the origin of the projection self.scale_factor_at_projection_origin = _arg_default( scale_factor_at_projection_origin, 0 ) From 15c0b30ca65cf884e4de272afca2a264cc97c175 Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Tue, 22 Feb 2022 15:19:21 +0000 Subject: [PATCH 4/9] Initial test changes --- lib/iris/tests/test_netcdf.py | 6 ++++ .../actions/test__grid_mappings.py | 33 +++---------------- .../test_has_supported_mercator_parameters.py | 20 ++++++++++- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/lib/iris/tests/test_netcdf.py b/lib/iris/tests/test_netcdf.py index 8cdbe27257..a11cd54c77 100644 --- a/lib/iris/tests/test_netcdf.py +++ b/lib/iris/tests/test_netcdf.py @@ -228,6 +228,12 @@ def test_load_merc_false_en_grid(self): ) self.assertCML(cube, ("netcdf", "netcdf_merc_false.cml")) + def test_load_merc_non_unit_scale_factor(self): + raise NotImplementedError + + def test_load_merc_standard_parallel(self): + raise NotImplementedError + def test_load_stereographic_grid(self): # Test loading a single CF-netCDF file with a stereographic # grid_mapping. diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py index a2ecdf1490..1bf9226092 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py @@ -445,7 +445,7 @@ def test_mapping_rotated(self): # # All non-latlon coordinate systems ... # These all have projection-x/y coordinates with units of metres. - # They all work the same way, except that Mercator/Stereographic have + # They all work the same way, except that Stereographic has # parameter checking routines that can fail. # NOTE: various mapping types *require* certain addtional properties # - without which an error will occur during translation. @@ -490,37 +490,12 @@ def test_mapping_mercator(self): ) self.check_result(result, cube_cstype=ics.Mercator) - def test_mapping_mercator__fail_unsupported(self): - # Provide a mercator grid-mapping with a non-unity scale factor, which - # we cannot handle. - # Result : fails to convert into a coord-system, and emits a warning. - # - # Rules Triggered: - # 001 : fc_default - # 002 : fc_provides_grid_mapping_(mercator) --(FAILED check has_supported_mercator_parameters) - # 003 : fc_provides_coordinate_(projection_y) - # 004 : fc_provides_coordinate_(projection_x) - # 005 : fc_build_coordinate_(projection_y)(FAILED projected coord with non-projected cs) - # 006 : fc_build_coordinate_(projection_x)(FAILED projected coord with non-projected cs) - # Notes: - # * grid-mapping identified : NONE - # * dim-coords identified : proj-x and -y - # * coords built : NONE (no dim or aux coords: cube has no coords) - warning = "not yet supported for Mercator" - result = self.run_testcase( - warning=warning, - mapping_type_name=hh.CF_GRID_MAPPING_MERCATOR, - mapping_scalefactor=2.0, - ) - self.check_result(result, cube_no_cs=True, cube_no_xycoords=True) - def test_mapping_stereographic(self): result = self.run_testcase(mapping_type_name=hh.CF_GRID_MAPPING_STEREO) self.check_result(result, cube_cstype=ics.Stereographic) def test_mapping_stereographic__fail_unsupported(self): - # As for 'test_mapping_mercator__fail_unsupported', provide a non-unity - # scale factor, which we cannot handle. + # Provide a non-unity scale factor, which we cannot handle. # Result : fails to convert into a coord-system, and emits a warning. # # Rules Triggered: @@ -531,7 +506,9 @@ def test_mapping_stereographic__fail_unsupported(self): # 005 : fc_build_coordinate_(projection_y)(FAILED projected coord with non-projected cs) # 006 : fc_build_coordinate_(projection_x)(FAILED projected coord with non-projected cs) # Notes: - # as for 'mercator__fail_unsupported', above + # * grid-mapping identified : NONE + # * dim-coords identified : proj-x and -y + # * coords built : NONE (no dim or aux coords: cube has no coords) warning = "not yet supported for stereographic" result = self.run_testcase( warning=warning, diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py index 1b9857c0be..14842b16f6 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py @@ -79,7 +79,25 @@ def test_valid_standard_parallel(self): self.assertTrue(is_valid) - def test_invalid_scale_factor(self): + def test_valid_scale_factor(self): + cf_name = "mercator" + cf_grid_var = mock.Mock( + spec=[], + longitude_of_projection_origin=0, + false_easting=0, + false_northing=0, + scale_factor_at_projection_origin=0.9, + semi_major_axis=6377563.396, + semi_minor_axis=6356256.909, + ) + engine = _engine(cf_grid_var, cf_name) + + is_valid = has_supported_mercator_parameters(engine, cf_name) + + self.assertTrue(is_valid) + + def test_invalid_scale_factor_and_standard_parallel(self): + raise NotImplementedError # Iris does not yet support scale factors other than one for # Mercator projections cf_name = "mercator" From bfe6dc58980204aff40fc7ae408b3eb10386b3de Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Wed, 23 Feb 2022 11:44:09 +0000 Subject: [PATCH 5/9] Test updates and additions --- .../tests/unit/coord_systems/test_Mercator.py | 58 +++++++++++++++++++ .../test_build_mercator_coordinate_system.py | 52 ++++++++++++++++- .../test_has_supported_mercator_parameters.py | 10 +++- 3 files changed, 116 insertions(+), 4 deletions(-) diff --git a/lib/iris/tests/unit/coord_systems/test_Mercator.py b/lib/iris/tests/unit/coord_systems/test_Mercator.py index 8a37a8fcc5..ba04c77d57 100644 --- a/lib/iris/tests/unit/coord_systems/test_Mercator.py +++ b/lib/iris/tests/unit/coord_systems/test_Mercator.py @@ -30,6 +30,7 @@ def test_repr(self): "ellipsoid=GeogCS(semi_major_axis=6377563.396, " "semi_minor_axis=6356256.909), " "standard_parallel=0.0, " + "scale_factor_at_projection_origin=None, " "false_easting=0.0, false_northing=0.0)" ) self.assertEqual(expected, repr(self.tm)) @@ -49,6 +50,13 @@ def test_set_optional_args(self): self.assertEqualAndKind(crs.false_easting, 13.0) self.assertEqualAndKind(crs.false_northing, 12.0) + def test_set_optional_scale_factor_alternative(self): + # Check that setting the optional (non-ellipse) args works. + crs = Mercator( + scale_factor_at_projection_origin=1.3, + ) + self.assertEqualAndKind(crs.scale_factor_at_projection_origin, 1.3) + def _check_crs_defaults(self, crs): # Check for property defaults when no kwargs options were set. # NOTE: except ellipsoid, which is done elsewhere. @@ -56,6 +64,7 @@ def _check_crs_defaults(self, crs): self.assertEqualAndKind(crs.standard_parallel, 0.0) self.assertEqualAndKind(crs.false_easting, 0.0) self.assertEqualAndKind(crs.false_northing, 0.0) + self.assertEqualAndKind(crs.scale_factor_at_projection_origin, None) def test_no_optional_args(self): # Check expected defaults with no optional args. @@ -67,6 +76,7 @@ def test_optional_args_None(self): crs = Mercator( longitude_of_projection_origin=None, standard_parallel=None, + scale_factor_at_projection_origin=None, false_easting=None, false_northing=None, ) @@ -117,6 +127,31 @@ def test_extra_kwargs(self): res = merc_cs.as_cartopy_crs() self.assertEqual(res, expected) + def test_extra_kwargs_scale_factor_alternative(self): + # Check that a projection with non-default values is correctly + # converted to a cartopy CRS. + scale_factor_at_projection_origin = 1.3 + ellipsoid = GeogCS( + semi_major_axis=6377563.396, semi_minor_axis=6356256.909 + ) + + merc_cs = Mercator( + ellipsoid=ellipsoid, + scale_factor_at_projection_origin=scale_factor_at_projection_origin, + ) + + expected = ccrs.Mercator( + globe=ccrs.Globe( + semimajor_axis=6377563.396, + semiminor_axis=6356256.909, + ellipse=None, + ), + scale_factor=scale_factor_at_projection_origin, + ) + + res = merc_cs.as_cartopy_crs() + self.assertEqual(res, expected) + class Test_as_cartopy_projection(tests.IrisTest): def test_simple(self): @@ -159,6 +194,29 @@ def test_extra_kwargs(self): res = merc_cs.as_cartopy_projection() self.assertEqual(res, expected) + def test_extra_kwargs_scale_factor_alternative(self): + ellipsoid = GeogCS( + semi_major_axis=6377563.396, semi_minor_axis=6356256.909 + ) + scale_factor_at_projection_origin = 1.3 + + merc_cs = Mercator( + ellipsoid=ellipsoid, + scale_factor_at_projection_origin=scale_factor_at_projection_origin, + ) + + expected = ccrs.Mercator( + globe=ccrs.Globe( + semimajor_axis=6377563.396, + semiminor_axis=6356256.909, + ellipse=None, + ), + scale_factor=scale_factor_at_projection_origin, + ) + + res = merc_cs.as_cartopy_projection() + self.assertEqual(res, expected) + if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_mercator_coordinate_system.py b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_mercator_coordinate_system.py index 2be5477cb7..ab61d3b1b2 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_mercator_coordinate_system.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_mercator_coordinate_system.py @@ -29,6 +29,7 @@ def test_valid(self): longitude_of_projection_origin=-90, semi_major_axis=6377563.396, semi_minor_axis=6356256.909, + standard_parallel=10, ) cs = build_mercator_coordinate_system(None, cf_grid_var) @@ -40,6 +41,7 @@ def test_valid(self): ellipsoid=iris.coord_systems.GeogCS( cf_grid_var.semi_major_axis, cf_grid_var.semi_minor_axis ), + standard_parallel=(cf_grid_var.standard_parallel), ) self.assertEqual(cs, expected) @@ -49,6 +51,7 @@ def test_inverse_flattening(self): longitude_of_projection_origin=-90, semi_major_axis=6377563.396, inverse_flattening=299.3249646, + standard_parallel=10, ) cs = build_mercator_coordinate_system(None, cf_grid_var) @@ -61,6 +64,7 @@ def test_inverse_flattening(self): cf_grid_var.semi_major_axis, inverse_flattening=cf_grid_var.inverse_flattening, ), + standard_parallel=(cf_grid_var.standard_parallel), ) self.assertEqual(cs, expected) @@ -69,6 +73,7 @@ def test_longitude_missing(self): spec=[], semi_major_axis=6377563.396, inverse_flattening=299.3249646, + standard_parallel=10, ) cs = build_mercator_coordinate_system(None, cf_grid_var) @@ -77,7 +82,52 @@ def test_longitude_missing(self): ellipsoid=iris.coord_systems.GeogCS( cf_grid_var.semi_major_axis, inverse_flattening=cf_grid_var.inverse_flattening, - ) + ), + standard_parallel=(cf_grid_var.standard_parallel), + ) + self.assertEqual(cs, expected) + + def test_standard_parallel_missing(self): + cf_grid_var = mock.Mock( + spec=[], + longitude_of_projection_origin=-90, + semi_major_axis=6377563.396, + semi_minor_axis=6356256.909, + ) + + cs = build_mercator_coordinate_system(None, cf_grid_var) + + expected = Mercator( + longitude_of_projection_origin=( + cf_grid_var.longitude_of_projection_origin + ), + ellipsoid=iris.coord_systems.GeogCS( + cf_grid_var.semi_major_axis, cf_grid_var.semi_minor_axis + ), + ) + self.assertEqual(cs, expected) + + def test_scale_factor_at_projection_origin(self): + cf_grid_var = mock.Mock( + spec=[], + longitude_of_projection_origin=-90, + semi_major_axis=6377563.396, + semi_minor_axis=6356256.909, + scale_factor_at_projection_origin=1.3, + ) + + cs = build_mercator_coordinate_system(None, cf_grid_var) + + expected = Mercator( + longitude_of_projection_origin=( + cf_grid_var.longitude_of_projection_origin + ), + ellipsoid=iris.coord_systems.GeogCS( + cf_grid_var.semi_major_axis, cf_grid_var.semi_minor_axis + ), + scale_factor_at_projection_origin=( + cf_grid_var.scale_factor_at_projection_origin + ), ) self.assertEqual(cs, expected) diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py index 14842b16f6..bb94adc72e 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_has_supported_mercator_parameters.py @@ -97,8 +97,7 @@ def test_valid_scale_factor(self): self.assertTrue(is_valid) def test_invalid_scale_factor_and_standard_parallel(self): - raise NotImplementedError - # Iris does not yet support scale factors other than one for + # Scale factor and standard parallel cannot both be specified for # Mercator projections cf_name = "mercator" cf_grid_var = mock.Mock( @@ -107,6 +106,7 @@ def test_invalid_scale_factor_and_standard_parallel(self): false_easting=0, false_northing=0, scale_factor_at_projection_origin=0.9, + standard_parallel=20, semi_major_axis=6377563.396, semi_minor_axis=6356256.909, ) @@ -118,7 +118,11 @@ def test_invalid_scale_factor_and_standard_parallel(self): self.assertFalse(is_valid) self.assertEqual(len(warns), 1) - self.assertRegex(str(warns[0]), "Scale factor") + self.assertRegex( + str(warns[0]), + "both " + '"scale_factor_at_projection_origin" and "standard_parallel"', + ) if __name__ == "__main__": From f2883a97b8d5d6b90917eee2b323f46dcb3e33d9 Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Thu, 24 Feb 2022 10:04:18 +0000 Subject: [PATCH 6/9] New expected test outputs --- .../tests/results/coord_systems/Mercator.xml | 2 +- lib/iris/tests/results/netcdf/netcdf_merc.cml | 8 +++---- .../results/netcdf/netcdf_merc_false.cml | 8 +++---- .../netcdf/netcdf_merc_scale_factor.cml | 22 +++++++++++++++++++ .../netcdf/Saver/write/mercator.cdl | 2 +- .../Saver/write/mercator_no_ellipsoid.cdl | 2 +- lib/iris/tests/test_netcdf.py | 18 +++++++++------ 7 files changed, 44 insertions(+), 18 deletions(-) create mode 100644 lib/iris/tests/results/netcdf/netcdf_merc_scale_factor.cml diff --git a/lib/iris/tests/results/coord_systems/Mercator.xml b/lib/iris/tests/results/coord_systems/Mercator.xml index db3ccffec7..4ea768b41e 100644 --- a/lib/iris/tests/results/coord_systems/Mercator.xml +++ b/lib/iris/tests/results/coord_systems/Mercator.xml @@ -1,2 +1,2 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_merc.cml b/lib/iris/tests/results/netcdf/netcdf_merc.cml index 5e17400158..831a8fdaa7 100644 --- a/lib/iris/tests/results/netcdf/netcdf_merc.cml +++ b/lib/iris/tests/results/netcdf/netcdf_merc.cml @@ -53,15 +53,15 @@ 45.5158, 45.9993]]" shape="(192, 192)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="lon"/> - - + - - + diff --git a/lib/iris/tests/results/netcdf/netcdf_merc_false.cml b/lib/iris/tests/results/netcdf/netcdf_merc_false.cml index d916f5f753..1e50aa6e65 100644 --- a/lib/iris/tests/results/netcdf/netcdf_merc_false.cml +++ b/lib/iris/tests/results/netcdf/netcdf_merc_false.cml @@ -6,17 +6,17 @@ - - + - - + diff --git a/lib/iris/tests/results/netcdf/netcdf_merc_scale_factor.cml b/lib/iris/tests/results/netcdf/netcdf_merc_scale_factor.cml new file mode 100644 index 0000000000..c9ad4ca33f --- /dev/null +++ b/lib/iris/tests/results/netcdf/netcdf_merc_scale_factor.cml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator.cdl b/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator.cdl index 1559cd2bff..ea9a1c283b 100644 --- a/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator.cdl +++ b/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator.cdl @@ -13,7 +13,7 @@ variables: mercator:longitude_of_projection_origin = 49. ; mercator:false_easting = 0. ; mercator:false_northing = 0. ; - mercator:scale_factor_at_projection_origin = 1. ; + mercator:standard_parallel = 0. ; int64 projection_y_coordinate(projection_y_coordinate) ; projection_y_coordinate:axis = "Y" ; projection_y_coordinate:units = "m" ; diff --git a/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator_no_ellipsoid.cdl b/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator_no_ellipsoid.cdl index 8db60ca952..73b692ed63 100644 --- a/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator_no_ellipsoid.cdl +++ b/lib/iris/tests/results/unit/fileformats/netcdf/Saver/write/mercator_no_ellipsoid.cdl @@ -10,7 +10,7 @@ variables: mercator:longitude_of_projection_origin = 49. ; mercator:false_easting = 0. ; mercator:false_northing = 0. ; - mercator:scale_factor_at_projection_origin = 1. ; + mercator:standard_parallel = 0. ; int64 projection_y_coordinate(projection_y_coordinate) ; projection_y_coordinate:axis = "Y" ; projection_y_coordinate:units = "m" ; diff --git a/lib/iris/tests/test_netcdf.py b/lib/iris/tests/test_netcdf.py index a11cd54c77..4d130c0f0e 100644 --- a/lib/iris/tests/test_netcdf.py +++ b/lib/iris/tests/test_netcdf.py @@ -218,9 +218,9 @@ def test_load_merc_grid(self): ) self.assertCML(cube, ("netcdf", "netcdf_merc.cml")) - def test_load_merc_false_en_grid(self): + def test_load_complex_merc_grid(self): # Test loading a single CF-netCDF file with a Mercator grid_mapping that - # includes false easting and northing + # includes false easting and northing and a standard parallel cube = iris.load_cube( tests.get_data_path( ("NetCDF", "mercator", "false_east_north_merc.nc") @@ -228,11 +228,15 @@ def test_load_merc_false_en_grid(self): ) self.assertCML(cube, ("netcdf", "netcdf_merc_false.cml")) - def test_load_merc_non_unit_scale_factor(self): - raise NotImplementedError - - def test_load_merc_standard_parallel(self): - raise NotImplementedError + def test_load_merc_grid_non_unit_scale_factor(self): + # Test loading a single CF-netCDF file with a Mercator grid_mapping that + # includes a non-unit scale factor at projection origin + cube = iris.load_cube( + tests.get_data_path( + ("NetCDF", "mercator", "non_unit_scale_factor_merc.nc") + ) + ) + self.assertCML(cube, ("netcdf", "netcdf_merc_scale_factor.cml")) def test_load_stereographic_grid(self): # Test loading a single CF-netCDF file with a stereographic From 5c6efa875ab88808f2850a5e116e38fb7cf92917 Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Tue, 1 Mar 2022 13:52:05 +0000 Subject: [PATCH 7/9] What's new and test data version bump --- .cirrus.yml | 2 +- docs/src/whatsnew/latest.rst.template | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 534f9f895c..ea1a978b65 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -38,7 +38,7 @@ env: # Conda packages to be installed. CONDA_CACHE_PACKAGES: "nox pip" # Git commit hash for iris test data. - IRIS_TEST_DATA_VERSION: "2.7" + IRIS_TEST_DATA_VERSION: "2.8" # Base directory for the iris-test-data. IRIS_TEST_DATA_DIR: ${HOME}/iris-test-data diff --git a/docs/src/whatsnew/latest.rst.template b/docs/src/whatsnew/latest.rst.template index 1b36d3f0b0..3db54a9a5f 100644 --- a/docs/src/whatsnew/latest.rst.template +++ b/docs/src/whatsnew/latest.rst.template @@ -56,6 +56,10 @@ NOTE: section above is a template for bugfix patches #. N/A +#. `@wjbenfold`_ added support for CF-compliant treatment of + ``standard_parallel`` and ``scale_factor_at_projection_origin`` to + :class:`~iris.coord_system.Mercator`. (:issue:`3844`, :pull:`4609`) + 🐛 Bugs Fixed ============= From 27a3989744c97a0ab5402b671cd3f0f6dc9059a3 Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Fri, 22 Apr 2022 11:11:04 +0100 Subject: [PATCH 8/9] Review fix --- lib/iris/fileformats/netcdf.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/iris/fileformats/netcdf.py b/lib/iris/fileformats/netcdf.py index 3ee430084c..4818f621c8 100644 --- a/lib/iris/fileformats/netcdf.py +++ b/lib/iris/fileformats/netcdf.py @@ -2563,12 +2563,13 @@ def add_ellipsoid(ellipsoid): ) cf_var_grid.false_easting = cs.false_easting cf_var_grid.false_northing = cs.false_northing - if cs.scale_factor_at_projection_origin is not None: + # Only one of these should be set + if cs.standard_parallel is not None: + cf_var_grid.standard_parallel = cs.standard_parallel + elif cs.scale_factor_at_projection_origin is not None: cf_var_grid.scale_factor_at_projection_origin = ( cs.scale_factor_at_projection_origin ) - if cs.standard_parallel is not None: - cf_var_grid.standard_parallel = cs.standard_parallel # lcc elif isinstance(cs, iris.coord_systems.LambertConformal): From 4fd75d7bc10518a09f9597419fff6977c09ef480 Mon Sep 17 00:00:00 2001 From: Will Benfold Date: Fri, 22 Apr 2022 12:24:18 +0100 Subject: [PATCH 9/9] Edit the right file --- docs/src/whatsnew/latest.rst | 4 ++++ docs/src/whatsnew/latest.rst.template | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 3c62bb324a..3a76813b4c 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -40,6 +40,10 @@ This document explains the changes made to Iris for this release #. `@pp-mo`_ fixed cube arithmetic operation for cubes with meshes. (:issue:`4454`, :pull:`4651`) +#. `@wjbenfold`_ added support for CF-compliant treatment of + ``standard_parallel`` and ``scale_factor_at_projection_origin`` to + :class:`~iris.coord_system.Mercator`. (:issue:`3844`, :pull:`4609`) + 🐛 Bugs Fixed ============= diff --git a/docs/src/whatsnew/latest.rst.template b/docs/src/whatsnew/latest.rst.template index 3db54a9a5f..1b36d3f0b0 100644 --- a/docs/src/whatsnew/latest.rst.template +++ b/docs/src/whatsnew/latest.rst.template @@ -56,10 +56,6 @@ NOTE: section above is a template for bugfix patches #. N/A -#. `@wjbenfold`_ added support for CF-compliant treatment of - ``standard_parallel`` and ``scale_factor_at_projection_origin`` to - :class:`~iris.coord_system.Mercator`. (:issue:`3844`, :pull:`4609`) - 🐛 Bugs Fixed =============