diff --git a/docs/iris/src/whatsnew/latest.rst b/docs/iris/src/whatsnew/latest.rst
index a994a994e9..b030d2dc9b 100644
--- a/docs/iris/src/whatsnew/latest.rst
+++ b/docs/iris/src/whatsnew/latest.rst
@@ -92,6 +92,11 @@ Bugs Fixed
loading. They are now available on the :class:`~iris.coords.CellMeasure` in
the loaded :class:`~iris.cube.Cube`. See :pull:`3800`.
+* the netcdf loader can now handle any grid-mapping variables with missing
+ ``false_easting`` and ``false_northing`` properties, which was previously
+ failing for some coordinate systems.
+ See :issue:`3629`.
+
Incompatible Changes
====================
diff --git a/lib/iris/coord_systems.py b/lib/iris/coord_systems.py
index 812dfae23e..82d75ba2b8 100644
--- a/lib/iris/coord_systems.py
+++ b/lib/iris/coord_systems.py
@@ -15,6 +15,35 @@
import cartopy.crs as ccrs
+def _arg_default(value, default, cast_as=float):
+ """Apply a default value and type for an optional kwarg."""
+ if value is None:
+ value = default
+ value = cast_as(value)
+ return value
+
+
+def _1or2_parallels(arg):
+ """Accept 1 or 2 inputs as a tuple of 1 or 2 floats."""
+ try:
+ values_tuple = tuple(arg)
+ except TypeError:
+ values_tuple = (arg,)
+ values_tuple = tuple([float(x) for x in values_tuple])
+ nvals = len(values_tuple)
+ if nvals not in (1, 2):
+ emsg = "Allows only 1 or 2 parallels or secant latitudes : got {!r}"
+ raise ValueError(emsg.format(arg))
+ return values_tuple
+
+
+def _float_or_None(arg):
+ """Cast as float, except for allowing None as a distinct valid value."""
+ if arg is not None:
+ arg = float(arg)
+ return arg
+
+
class CoordSystem(metaclass=ABCMeta):
"""
Abstract base class for coordinate systems.
@@ -107,19 +136,24 @@ def __init__(
semi_major_axis=None,
semi_minor_axis=None,
inverse_flattening=None,
- longitude_of_prime_meridian=0,
+ longitude_of_prime_meridian=None,
):
"""
Creates a new GeogCS.
Kwargs:
- * semi_major_axis - of ellipsoid in metres
- * semi_minor_axis - of ellipsoid in metres
- * inverse_flattening - of ellipsoid
- * longitude_of_prime_meridian - Can be used to specify the
- prime meridian on the ellipsoid
- in degrees. Default = 0.
+ * semi_major_axis, semi_minor_axis:
+ Axes of ellipsoid, in metres. At least one must be given
+ (see note below).
+
+ * inverse_flattening:
+ Can be omitted if both axes given (see note below).
+ Defaults to 0.0 .
+
+ * longitude_of_prime_meridian:
+ Specifies the prime meridian on the ellipsoid, in degrees.
+ Defaults to 0.0 .
If just semi_major_axis is set, with no semi_minor_axis or
inverse_flattening, then a perfect sphere is created from the given
@@ -204,11 +238,13 @@ def __init__(
#: Minor radius of the ellipsoid in metres.
self.semi_minor_axis = float(semi_minor_axis)
- #: :math:`1/f` where :math:`f = (a-b)/a`
+ #: :math:`1/f` where :math:`f = (a-b)/a`.
self.inverse_flattening = float(inverse_flattening)
#: Describes 'zero' on the ellipsoid in degrees.
- self.longitude_of_prime_meridian = float(longitude_of_prime_meridian)
+ self.longitude_of_prime_meridian = _arg_default(
+ longitude_of_prime_meridian, 0
+ )
def _pretty_attrs(self):
attrs = [("semi_major_axis", self.semi_major_axis)]
@@ -285,7 +321,7 @@ def __init__(
self,
grid_north_pole_latitude,
grid_north_pole_longitude,
- north_pole_grid_longitude=0,
+ north_pole_grid_longitude=None,
ellipsoid=None,
):
"""
@@ -294,17 +330,20 @@ def __init__(
Args:
- * grid_north_pole_latitude - The true latitude of the rotated
- pole in degrees.
- * grid_north_pole_longitude - The true longitude of the rotated
- pole in degrees.
+ * grid_north_pole_latitude:
+ The true latitude of the rotated pole in degrees.
+
+ * grid_north_pole_longitude:
+ The true longitude of the rotated pole in degrees.
Kwargs:
- * north_pole_grid_longitude - Longitude of true north pole in
- rotated grid in degrees. Default = 0.
- * ellipsoid - Optional :class:`GeogCS` defining
- the ellipsoid.
+ * north_pole_grid_longitude:
+ Longitude of true north pole in rotated grid, in degrees.
+ Defaults to 0.0 .
+
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
Examples::
@@ -320,9 +359,11 @@ def __init__(
self.grid_north_pole_longitude = float(grid_north_pole_longitude)
#: Longitude of true north pole in rotated grid in degrees.
- self.north_pole_grid_longitude = float(north_pole_grid_longitude)
+ self.north_pole_grid_longitude = _arg_default(
+ north_pole_grid_longitude, 0
+ )
- #: Ellipsoid definition.
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def _pretty_attrs(self):
@@ -397,9 +438,9 @@ def __init__(
self,
latitude_of_projection_origin,
longitude_of_central_meridian,
- false_easting,
- false_northing,
- scale_factor_at_central_meridian,
+ false_easting=None,
+ false_northing=None,
+ scale_factor_at_central_meridian=None,
ellipsoid=None,
):
"""
@@ -407,27 +448,30 @@ def __init__(
Args:
- * latitude_of_projection_origin
- True latitude of planar origin in degrees.
+ * latitude_of_projection_origin:
+ True latitude of planar origin in degrees.
- * longitude_of_central_meridian
- True longitude of planar origin in degrees.
+ * longitude_of_central_meridian:
+ True longitude of planar origin in degrees.
- * false_easting
- X offset from planar origin in metres.
+ Kwargs:
- * false_northing
- Y offset from planar origin in metres.
+ * false_easting:
+ X offset from planar origin in metres.
+ Defaults to 0.0 .
- * scale_factor_at_central_meridian
- Reduces the cylinder to slice through the ellipsoid
- (secant form). Used to provide TWO longitudes of zero
- distortion in the area of interest.
+ * false_northing:
+ Y offset from planar origin in metres.
+ Defaults to 0.0 .
- Kwargs:
+ * scale_factor_at_central_meridian:
+ Reduces the cylinder to slice through the ellipsoid
+ (secant form). Used to provide TWO longitudes of zero
+ distortion in the area of interest.
+ Defaults to 1.0 .
- * ellipsoid
- Optional :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
Example::
@@ -447,17 +491,17 @@ def __init__(
)
#: X offset from planar origin in metres.
- self.false_easting = float(false_easting)
+ self.false_easting = _arg_default(false_easting, 0)
#: Y offset from planar origin in metres.
- self.false_northing = float(false_northing)
+ self.false_northing = _arg_default(false_northing, 0)
- #: Reduces the cylinder to slice through the ellipsoid (secant form).
- self.scale_factor_at_central_meridian = float(
- scale_factor_at_central_meridian
+ #: Scale factor at the centre longitude.
+ self.scale_factor_at_central_meridian = _arg_default(
+ scale_factor_at_central_meridian, 1.0
)
- #: Ellipsoid definition.
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -524,8 +568,8 @@ def __init__(
self,
latitude_of_projection_origin,
longitude_of_projection_origin,
- false_easting=0.0,
- false_northing=0.0,
+ false_easting=None,
+ false_northing=None,
ellipsoid=None,
):
"""
@@ -541,14 +585,14 @@ def __init__(
Kwargs:
- * false_easting
- X offset from planar origin in metres. Defaults to 0.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_northing
- Y offset from planar origin in metres. Defaults to 0.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
"""
#: True latitude of planar origin in degrees.
@@ -562,12 +606,12 @@ def __init__(
)
#: X offset from planar origin in metres.
- self.false_easting = float(false_easting)
+ self.false_easting = _arg_default(false_easting, 0)
#: Y offset from planar origin in metres.
- self.false_northing = float(false_northing)
+ self.false_northing = _arg_default(false_northing, 0)
- #: Ellipsoid definition.
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -615,8 +659,8 @@ def __init__(
latitude_of_projection_origin,
longitude_of_projection_origin,
perspective_point_height,
- false_easting=0,
- false_northing=0,
+ false_easting=None,
+ false_northing=None,
ellipsoid=None,
):
"""
@@ -636,14 +680,14 @@ def __init__(
Kwargs:
- * false_easting
- X offset from planar origin in metres. Defaults to 0.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_northing
- Y offset from planar origin in metres. Defaults to 0.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
"""
#: True latitude of planar origin in degrees.
@@ -657,16 +701,16 @@ def __init__(
)
#: Altitude of satellite in metres.
- # test if perspective_point_height may be cast to float for proj.4
self.perspective_point_height = float(perspective_point_height)
+ # TODO: test if may be cast to float for proj.4
#: X offset from planar origin in metres.
- self.false_easting = float(false_easting)
+ self.false_easting = _arg_default(false_easting, 0)
#: Y offset from planar origin in metres.
- self.false_northing = float(false_northing)
+ self.false_northing = _arg_default(false_northing, 0)
- #: Ellipsoid definition.
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -725,13 +769,13 @@ def __init__(
Args:
- * latitude_of_projection_origin (float):
+ * latitude_of_projection_origin:
True latitude of planar origin in degrees.
- * longitude_of_projection_origin (float):
+ * longitude_of_projection_origin:
True longitude of planar origin in degrees.
- * perspective_point_height (float):
+ * perspective_point_height:
Altitude of satellite in metres above the surface of the ellipsoid.
* sweep_angle_axis (string):
@@ -739,14 +783,14 @@ def __init__(
Kwargs:
- * false_easting (float):
- X offset from planar origin in metres. Defaults to 0.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_northing (float):
- Y offset from planar origin in metres. Defaults to 0.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * ellipsoid (iris.coord_systems.GeogCS):
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
"""
#: True latitude of planar origin in degrees.
@@ -765,25 +809,21 @@ def __init__(
)
#: Altitude of satellite in metres.
- # test if perspective_point_height may be cast to float for proj.4
self.perspective_point_height = float(perspective_point_height)
+ # TODO: test if may be cast to float for proj.4
#: X offset from planar origin in metres.
- if false_easting is None:
- false_easting = 0
- self.false_easting = float(false_easting)
+ self.false_easting = _arg_default(false_easting, 0)
#: Y offset from planar origin in metres.
- if false_northing is None:
- false_northing = 0
- self.false_northing = float(false_northing)
+ self.false_northing = _arg_default(false_northing, 0)
- #: The axis along which the satellite instrument sweeps - 'x' or 'y'.
+ #: The sweep angle axis (string 'x' or 'y').
self.sweep_angle_axis = sweep_angle_axis
if self.sweep_angle_axis not in ("x", "y"):
raise ValueError('Invalid sweep_angle_axis - must be "x" or "y"')
- #: Ellipsoid definition.
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -831,8 +871,8 @@ def __init__(
self,
central_lat,
central_lon,
- false_easting=0.0,
- false_northing=0.0,
+ false_easting=None,
+ false_northing=None,
true_scale_lat=None,
ellipsoid=None,
):
@@ -841,25 +881,25 @@ def __init__(
Args:
- * central_lat
- The latitude of the pole.
+ * central_lat:
+ The latitude of the pole.
- * central_lon
- The central longitude, which aligns with the y axis.
+ * central_lon:
+ The central longitude, which aligns with the y axis.
Kwargs:
- * false_easting
- X offset from planar origin in metres. Defaults to 0.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_northing
- Y offset from planar origin in metres. Defaults to 0.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * true_scale_lat
- Latitude of true scale.
+ * true_scale_lat:
+ Latitude of true scale.
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
"""
@@ -870,15 +910,19 @@ def __init__(
self.central_lon = float(central_lon)
#: X offset from planar origin in metres.
- self.false_easting = float(false_easting)
+ self.false_easting = _arg_default(false_easting, 0)
#: Y offset from planar origin in metres.
- self.false_northing = float(false_northing)
+ self.false_northing = _arg_default(false_northing, 0)
#: Latitude of true scale.
- self.true_scale_lat = float(true_scale_lat) if true_scale_lat else None
+ self.true_scale_lat = _arg_default(
+ true_scale_lat, None, cast_as=_float_or_None
+ )
+ # N.B. the way we use this parameter, we need it to default to None,
+ # and *not* to 0.0 .
- #: Ellipsoid definition.
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -922,11 +966,11 @@ class LambertConformal(CoordSystem):
def __init__(
self,
- central_lat=39.0,
- central_lon=-96.0,
- false_easting=0.0,
- false_northing=0.0,
- secant_latitudes=(33, 45),
+ central_lat=None,
+ central_lon=None,
+ false_easting=None,
+ false_northing=None,
+ secant_latitudes=None,
ellipsoid=None,
):
"""
@@ -934,23 +978,24 @@ def __init__(
Kwargs:
- * central_lat
- The latitude of "unitary scale".
+ * central_lat:
+ The latitude of "unitary scale". Defaults to 39.0 .
- * central_lon
- The central longitude.
+ * central_lon:
+ The central longitude. Defaults to -96.0 .
- * false_easting
- X offset from planar origin in metres.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_northing
- Y offset from planar origin in metres.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * secant_latitudes
- Latitudes of secant intersection.
+ * secant_latitudes (number or iterable of 1 or 2 numbers):
+ Latitudes of secant intersection. One or two.
+ Defaults to (33.0, 45.0).
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
.. note:
@@ -962,23 +1007,23 @@ def __init__(
"""
#: True latitude of planar origin in degrees.
- self.central_lat = central_lat
+ self.central_lat = _arg_default(central_lat, 39.0)
+
#: True longitude of planar origin in degrees.
- self.central_lon = central_lon
+ self.central_lon = _arg_default(central_lon, -96.0)
+
#: X offset from planar origin in metres.
- self.false_easting = false_easting
+ self.false_easting = _arg_default(false_easting, 0)
+
#: Y offset from planar origin in metres.
- self.false_northing = false_northing
- #: The one or two standard parallels of the cone.
- try:
- self.secant_latitudes = tuple(secant_latitudes)
- except TypeError:
- self.secant_latitudes = (secant_latitudes,)
- nlats = len(self.secant_latitudes)
- if nlats == 0 or nlats > 2:
- emsg = "Either one or two secant latitudes required, got {}"
- raise ValueError(emsg.format(nlats))
- #: Ellipsoid definition.
+ self.false_northing = _arg_default(false_northing, 0)
+
+ #: The standard parallels of the cone (tuple of 1 or 2 floats).
+ self.secant_latitudes = _arg_default(
+ secant_latitudes, (33, 45), cast_as=_1or2_parallels
+ )
+
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -1032,28 +1077,35 @@ class Mercator(CoordSystem):
def __init__(
self,
- longitude_of_projection_origin=0.0,
+ longitude_of_projection_origin=None,
ellipsoid=None,
- standard_parallel=0.0,
+ standard_parallel=None,
):
"""
Constructs a Mercator coord system.
Kwargs:
- * longitude_of_projection_origin
- True longitude of planar origin in degrees.
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
- * standard_parallel
- the latitude where the scale is 1. Defaults to 0 degrees.
+
+ * longitude_of_projection_origin:
+ True longitude of planar origin in degrees. Defaults to 0.0 .
+
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
+
+ * standard_parallel:
+ The latitude where the scale is 1. Defaults to 0.0 .
"""
#: True longitude of planar origin in degrees.
- self.longitude_of_projection_origin = longitude_of_projection_origin
- #: Ellipsoid definition.
+ self.longitude_of_projection_origin = _arg_default(
+ longitude_of_projection_origin, 0
+ )
+
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
- #: The latitude where the scale is 1 (defaults to 0 degrees).
- self.standard_parallel = standard_parallel
+
+ #: The latitude where the scale is 1.
+ self.standard_parallel = _arg_default(standard_parallel, 0)
def __repr__(self):
res = (
@@ -1087,10 +1139,10 @@ class LambertAzimuthalEqualArea(CoordSystem):
def __init__(
self,
- latitude_of_projection_origin=0.0,
- longitude_of_projection_origin=0.0,
- false_easting=0.0,
- false_northing=0.0,
+ latitude_of_projection_origin=None,
+ longitude_of_projection_origin=None,
+ false_easting=None,
+ false_northing=None,
ellipsoid=None,
):
"""
@@ -1098,31 +1150,39 @@ def __init__(
Kwargs:
- * latitude_of_projection_origin
- True latitude of planar origin in degrees. Defaults to 0.
+ * latitude_of_projection_origin:
+ True latitude of planar origin in degrees. Defaults to 0.0 .
- * longitude_of_projection_origin
- True longitude of planar origin in degrees. Defaults to 0.
+ * longitude_of_projection_origin:
+ True longitude of planar origin in degrees. Defaults to 0.0 .
- * false_easting
- X offset from planar origin in metres. Defaults to 0.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_northing
- Y offset from planar origin in metres. Defaults to 0.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
"""
#: True latitude of planar origin in degrees.
- self.latitude_of_projection_origin = latitude_of_projection_origin
+ self.latitude_of_projection_origin = _arg_default(
+ latitude_of_projection_origin, 0
+ )
+
#: True longitude of planar origin in degrees.
- self.longitude_of_projection_origin = longitude_of_projection_origin
+ self.longitude_of_projection_origin = _arg_default(
+ longitude_of_projection_origin, 0
+ )
+
#: X offset from planar origin in metres.
- self.false_easting = false_easting
+ self.false_easting = _arg_default(false_easting, 0)
+
#: Y offset from planar origin in metres.
- self.false_northing = false_northing
- #: Ellipsoid definition.
+ self.false_northing = _arg_default(false_northing, 0)
+
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
@@ -1163,11 +1223,11 @@ class AlbersEqualArea(CoordSystem):
def __init__(
self,
- latitude_of_projection_origin=0.0,
- longitude_of_central_meridian=0.0,
- false_easting=0.0,
- false_northing=0.0,
- standard_parallels=(20.0, 50.0),
+ latitude_of_projection_origin=None,
+ longitude_of_central_meridian=None,
+ false_easting=None,
+ false_northing=None,
+ standard_parallels=None,
ellipsoid=None,
):
"""
@@ -1175,38 +1235,49 @@ def __init__(
Kwargs:
- * latitude_of_projection_origin
- True latitude of planar origin in degrees.
- Defaults to 0.
+ * latitude_of_projection_origin:
+ True latitude of planar origin in degrees. Defaults to 0.0 .
+
+ * longitude_of_central_meridian:
+ True longitude of planar central meridian in degrees.
+ Defaults to 0.0 .
- * longitude_of_central_meridian
- True longitude of planar central meridian in degrees.
- Defaults to 0.
+ * false_easting:
+ X offset from planar origin in metres. Defaults to 0.0 .
- * false_easting
- X offset from planar origin in metres. Defaults to 0.
+ * false_northing:
+ Y offset from planar origin in metres. Defaults to 0.0 .
- * false_northing
- Y offset from planar origin in metres. Defaults to 0.
+ * standard_parallels (number or iterable of 1 or 2 numbers):
+ The one or two latitudes of correct scale.
+ Defaults to (20.0, 50.0).
- * standard_parallels
- The one or two latitudes of correct scale.
- Defaults to (20,50).
- * ellipsoid
- :class:`GeogCS` defining the ellipsoid.
+ * ellipsoid (:class:`GeogCS`):
+ If given, defines the ellipsoid.
"""
#: True latitude of planar origin in degrees.
- self.latitude_of_projection_origin = latitude_of_projection_origin
+ self.latitude_of_projection_origin = _arg_default(
+ latitude_of_projection_origin, 0
+ )
+
#: True longitude of planar central meridian in degrees.
- self.longitude_of_central_meridian = longitude_of_central_meridian
+ self.longitude_of_central_meridian = _arg_default(
+ longitude_of_central_meridian, 0
+ )
+
#: X offset from planar origin in metres.
- self.false_easting = false_easting
+ self.false_easting = _arg_default(false_easting, 0)
+
#: Y offset from planar origin in metres.
- self.false_northing = false_northing
- #: The one or two latitudes of correct scale.
- self.standard_parallels = standard_parallels
- #: Ellipsoid definition.
+ self.false_northing = _arg_default(false_northing, 0)
+
+ #: The one or two latitudes of correct scale (tuple of 1 or 2 floats).
+ self.standard_parallels = _arg_default(
+ standard_parallels, (20, 50), cast_as=_1or2_parallels
+ )
+
+ #: Ellipsoid definition (:class:`GeogCS` or None).
self.ellipsoid = ellipsoid
def __repr__(self):
diff --git a/lib/iris/tests/__init__.py b/lib/iris/tests/__init__.py
index b5b80a97ef..2d97c62506 100644
--- a/lib/iris/tests/__init__.py
+++ b/lib/iris/tests/__init__.py
@@ -1077,6 +1077,13 @@ def assertDictEqual(self, lhs, rhs, msg=None):
)
raise AssertionError(emsg)
+ def assertEqualAndKind(self, value, expected):
+ # Check a value, and also its type 'kind' = float/integer/string.
+ self.assertEqual(value, expected)
+ self.assertEqual(
+ np.array(value).dtype.kind, np.array(expected).dtype.kind
+ )
+
# An environment variable controls whether test timings are output.
#
diff --git a/lib/iris/tests/results/netcdf/netcdf_laea.cml b/lib/iris/tests/results/netcdf/netcdf_laea.cml
index 03fdb529a4..ad23114038 100644
--- a/lib/iris/tests/results/netcdf/netcdf_laea.cml
+++ b/lib/iris/tests/results/netcdf/netcdf_laea.cml
@@ -31,12 +31,12 @@
[5262500.0, 5701785.71429],
[5701785.71429, 6141071.42857],
[6141071.42857, 6580357.14286],
- [6580357.14286, 7019642.85714]]" id="950c6ce8" points="[650000.0, 1089285.71429, 1528571.42857,
+ [6580357.14286, 7019642.85714]]" id="b71cdf0e" points="[650000.0, 1089285.71429, 1528571.42857,
1967857.14286, 2407142.85714, 2846428.57143,
3285714.28571, 3725000.0, 4164285.71429,
4603571.42857, 5042857.14286, 5482142.85714,
5921428.57143, 6360714.28571, 6800000.0]" shape="(15,)" standard_name="projection_x_coordinate" units="Unit('m')" value_type="float64" var_name="projection_x_coordinate">
-
+
@@ -54,12 +54,12 @@
[4500000.0, 4871428.57143],
[4871428.57143, 5242857.14286],
[5242857.14286, 5614285.71429],
- [5614285.71429, 5985714.28571]]" id="fbb8fa7a" points="[600000.0, 971428.571429, 1342857.14286,
+ [5614285.71429, 5985714.28571]]" id="f1f8b7cb" points="[600000.0, 971428.571429, 1342857.14286,
1714285.71429, 2085714.28571, 2457142.85714,
2828571.42857, 3200000.0, 3571428.57143,
3942857.14286, 4314285.71429, 4685714.28571,
5057142.85714, 5428571.42857, 5800000.0]" shape="(15,)" standard_name="projection_y_coordinate" units="Unit('m')" value_type="float64" var_name="projection_y_coordinate">
-
+
diff --git a/lib/iris/tests/results/netcdf/netcdf_lcc.cml b/lib/iris/tests/results/netcdf/netcdf_lcc.cml
index ace6c632d9..7ea53e6600 100644
--- a/lib/iris/tests/results/netcdf/netcdf_lcc.cml
+++ b/lib/iris/tests/results/netcdf/netcdf_lcc.cml
@@ -48,7 +48,7 @@
..., 11.7454500198, 11.7587404251, 11.77202034]]" shape="(60, 60)" standard_name="longitude" units="Unit('degrees')" value_type="float64" var_name="lon"/>
-
-
+
-
-
+
diff --git a/lib/iris/tests/test_coordsystem.py b/lib/iris/tests/test_coordsystem.py
index 3b89215dba..5babf1a9e2 100644
--- a/lib/iris/tests/test_coordsystem.py
+++ b/lib/iris/tests/test_coordsystem.py
@@ -432,12 +432,12 @@ def test_as_cartopy_projection(self):
class Test_LambertConformal(tests.GraphicsTest):
def test_fail_secant_latitudes_none(self):
- emsg = "one or two secant latitudes required"
+ emsg = "secant latitudes"
with self.assertRaisesRegex(ValueError, emsg):
LambertConformal(secant_latitudes=())
def test_fail_secant_latitudes_excessive(self):
- emsg = "one or two secant latitudes required"
+ emsg = "secant latitudes"
with self.assertRaisesRegex(ValueError, emsg):
LambertConformal(secant_latitudes=(1, 2, 3))
diff --git a/lib/iris/tests/unit/coord_systems/test_AlbersEqualArea.py b/lib/iris/tests/unit/coord_systems/test_AlbersEqualArea.py
index 36e38e90d4..09e69feff9 100644
--- a/lib/iris/tests/unit/coord_systems/test_AlbersEqualArea.py
+++ b/lib/iris/tests/unit/coord_systems/test_AlbersEqualArea.py
@@ -52,6 +52,16 @@ def test_crs_creation(self):
)
self.assertEqual(res, expected)
+ def test_fail_too_few_parallels(self):
+ emsg = "parallels"
+ with self.assertRaisesRegex(ValueError, emsg):
+ AlbersEqualArea(standard_parallels=())
+
+ def test_fail_too_many_parallels(self):
+ emsg = "parallels"
+ with self.assertRaisesRegex(ValueError, emsg):
+ AlbersEqualArea(standard_parallels=(1, 2, 3))
+
class Test_as_cartopy_projection(tests.IrisTest):
def setUp(self):
@@ -90,5 +100,52 @@ def test_projection_creation(self):
self.assertEqual(res, expected)
+class Test_init_defaults(tests.IrisTest):
+ def test_set_optional_args(self):
+ # Check that setting optional arguments works as expected.
+ crs = AlbersEqualArea(
+ longitude_of_central_meridian=123,
+ latitude_of_projection_origin=-17,
+ false_easting=100,
+ false_northing=-200,
+ standard_parallels=(-37, 21.4),
+ )
+
+ self.assertEqualAndKind(crs.longitude_of_central_meridian, 123.0)
+ self.assertEqualAndKind(crs.latitude_of_projection_origin, -17.0)
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -200.0)
+ self.assertEqual(len(crs.standard_parallels), 2)
+ self.assertEqualAndKind(crs.standard_parallels[0], -37.0)
+ self.assertEqualAndKind(crs.standard_parallels[1], 21.4)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.longitude_of_central_meridian, 0.0)
+ self.assertEqualAndKind(crs.latitude_of_projection_origin, 0.0)
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+ self.assertEqual(len(crs.standard_parallels), 2)
+ self.assertEqualAndKind(crs.standard_parallels[0], 20.0)
+ self.assertEqualAndKind(crs.standard_parallels[1], 50.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = AlbersEqualArea()
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = AlbersEqualArea(
+ longitude_of_central_meridian=None,
+ latitude_of_projection_origin=None,
+ standard_parallels=None,
+ false_easting=None,
+ false_northing=None,
+ )
+ self._check_crs_defaults(crs)
+
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_GeogCS.py b/lib/iris/tests/unit/coord_systems/test_GeogCS.py
new file mode 100644
index 0000000000..c2882272a3
--- /dev/null
+++ b/lib/iris/tests/unit/coord_systems/test_GeogCS.py
@@ -0,0 +1,51 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""Unit tests for the :class:`iris.coord_systems.GeogCS` class."""
+
+# Import iris.tests first so that some things can be initialised before
+# importing anything else.
+import iris.tests as tests
+
+from iris.coord_systems import GeogCS
+
+
+class Test_init_defaults(tests.IrisTest):
+ # NOTE: most of the testing for GeogCS is in the legacy test module
+ # 'iris.tests.test_coordsystem'.
+ # This class *only* tests the defaults for optional constructor args.
+
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) argument works.
+ crs = GeogCS(1.0, longitude_of_prime_meridian=-85)
+ self.assertEqualAndKind(crs.longitude_of_prime_meridian, -85.0)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ radius = float(crs.semi_major_axis)
+ self.assertEqualAndKind(crs.semi_major_axis, radius) # just the kind
+ self.assertEqualAndKind(crs.semi_minor_axis, radius)
+ self.assertEqualAndKind(crs.inverse_flattening, 0.0)
+ self.assertEqualAndKind(crs.longitude_of_prime_meridian, 0.0)
+
+ def test_no_optional_args(self):
+ # Check expected properties with no optional args.
+ crs = GeogCS(1.0)
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected properties with optional args=None.
+ crs = GeogCS(
+ 1.0,
+ semi_minor_axis=None,
+ inverse_flattening=None,
+ longitude_of_prime_meridian=None,
+ )
+ self._check_crs_defaults(crs)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_Geostationary.py b/lib/iris/tests/unit/coord_systems/test_Geostationary.py
index 2c08a13872..d1418cc6de 100644
--- a/lib/iris/tests/unit/coord_systems/test_Geostationary.py
+++ b/lib/iris/tests/unit/coord_systems/test_Geostationary.py
@@ -15,15 +15,16 @@
class Test(tests.IrisTest):
def setUp(self):
- self.latitude_of_projection_origin = 0.0
- self.longitude_of_projection_origin = 0.0
- self.perspective_point_height = 35785831.0
- self.sweep_angle_axis = "y"
- self.false_easting = 0.0
- self.false_northing = 0.0
-
- self.semi_major_axis = 6377563.396
- self.semi_minor_axis = 6356256.909
+ # Set everything to non-default values.
+ self.latitude_of_projection_origin = 0 # For now, Cartopy needs =0.
+ self.longitude_of_projection_origin = 123.0
+ self.perspective_point_height = 9999.0
+ self.sweep_angle_axis = "x"
+ self.false_easting = 100.0
+ self.false_northing = -200.0
+
+ self.semi_major_axis = 4000.0
+ self.semi_minor_axis = 3900.0
self.ellipsoid = GeogCS(self.semi_major_axis, self.semi_minor_axis)
self.globe = ccrs.Globe(
semimajor_axis=self.semi_major_axis,
@@ -83,6 +84,32 @@ def test_invalid_sweep(self):
self.ellipsoid,
)
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = Geostationary(
+ 0, 0, 1000, "y", false_easting=100, false_northing=-200
+ )
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -200.0)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = Geostationary(0, 0, 1000, "y")
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = Geostationary(
+ 0, 0, 1000, "y", false_easting=None, false_northing=None
+ )
+ self._check_crs_defaults(crs)
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_LambertAzimuthalEqualArea.py b/lib/iris/tests/unit/coord_systems/test_LambertAzimuthalEqualArea.py
index c4a283c3b9..fd0d5e8f60 100644
--- a/lib/iris/tests/unit/coord_systems/test_LambertAzimuthalEqualArea.py
+++ b/lib/iris/tests/unit/coord_systems/test_LambertAzimuthalEqualArea.py
@@ -84,5 +84,43 @@ def test_projection_creation(self):
self.assertEqual(res, expected)
+class Test_init_defaults(tests.IrisTest):
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = LambertAzimuthalEqualArea(
+ longitude_of_projection_origin=123,
+ latitude_of_projection_origin=-37,
+ false_easting=100,
+ false_northing=-200,
+ )
+ self.assertEqualAndKind(crs.longitude_of_projection_origin, 123.0)
+ self.assertEqualAndKind(crs.latitude_of_projection_origin, -37.0)
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -200.0)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.longitude_of_projection_origin, 0.0)
+ self.assertEqualAndKind(crs.latitude_of_projection_origin, 0.0)
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = LambertAzimuthalEqualArea()
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = LambertAzimuthalEqualArea(
+ longitude_of_projection_origin=None,
+ latitude_of_projection_origin=None,
+ false_easting=None,
+ false_northing=None,
+ )
+ self._check_crs_defaults(crs)
+
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_LambertConformal.py b/lib/iris/tests/unit/coord_systems/test_LambertConformal.py
new file mode 100644
index 0000000000..da360fa81c
--- /dev/null
+++ b/lib/iris/tests/unit/coord_systems/test_LambertConformal.py
@@ -0,0 +1,78 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""Unit tests for the :class:`iris.coord_systems.LambertConformal` class."""
+
+# Import iris.tests first so that some things can be initialised before
+# importing anything else.
+import iris.tests as tests
+
+from iris.coord_systems import LambertConformal
+
+
+class Test_init_defaults(tests.IrisTest):
+ # NOTE: most of the testing for LambertConformal is in the legacy test
+ # module 'iris.tests.test_coordsystem'.
+ # This class *only* tests the defaults for optional constructor args.
+
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ # (Except secant_latitudes, which are done separately).
+ crs = LambertConformal(
+ central_lat=25.3,
+ central_lon=-172,
+ false_easting=100,
+ false_northing=-200,
+ )
+ self.assertEqualAndKind(crs.central_lat, 25.3)
+ self.assertEqualAndKind(crs.central_lon, -172.0)
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -200.0)
+
+ def test_set_one_parallel(self):
+ # Check that setting the optional (non-ellipse) args works.
+ # (Except secant_latitudes, which are done separately).
+ crs = LambertConformal(secant_latitudes=-44)
+ self.assertEqual(len(crs.secant_latitudes), 1)
+ self.assertEqualAndKind(crs.secant_latitudes[0], -44.0)
+
+ def test_set_two_parallels(self):
+ # Check that setting the optional (non-ellipse) args works.
+ # (Except secant_latitudes, which are done separately).
+ crs = LambertConformal(secant_latitudes=[43, -7])
+ self.assertEqual(len(crs.secant_latitudes), 2)
+ self.assertEqualAndKind(crs.secant_latitudes[0], 43.0)
+ self.assertEqualAndKind(crs.secant_latitudes[1], -7.0)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.central_lat, 39.0)
+ self.assertEqualAndKind(crs.central_lon, -96.0)
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+ self.assertEqual(len(crs.secant_latitudes), 2)
+ self.assertEqualAndKind(crs.secant_latitudes[0], 33.0)
+ self.assertEqualAndKind(crs.secant_latitudes[1], 45.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = LambertConformal()
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = LambertConformal(
+ central_lat=None,
+ central_lon=None,
+ false_easting=None,
+ false_northing=None,
+ secant_latitudes=None,
+ )
+ self._check_crs_defaults(crs)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_Mercator.py b/lib/iris/tests/unit/coord_systems/test_Mercator.py
index 65668c895c..d48f81f61e 100644
--- a/lib/iris/tests/unit/coord_systems/test_Mercator.py
+++ b/lib/iris/tests/unit/coord_systems/test_Mercator.py
@@ -33,6 +33,34 @@ def test_repr(self):
self.assertEqual(expected, repr(self.tm))
+class Test_init_defaults(tests.IrisTest):
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = Mercator(
+ longitude_of_projection_origin=27, standard_parallel=157.4
+ )
+ self.assertEqualAndKind(crs.longitude_of_projection_origin, 27.0)
+ self.assertEqualAndKind(crs.standard_parallel, 157.4)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.longitude_of_projection_origin, 0.0)
+ self.assertEqualAndKind(crs.standard_parallel, 0.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = Mercator()
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = Mercator(
+ longitude_of_projection_origin=None, standard_parallel=None
+ )
+ self._check_crs_defaults(crs)
+
+
class Test_Mercator__as_cartopy_crs(tests.IrisTest):
def test_simple(self):
# Check that a projection set up with all the defaults is correctly
diff --git a/lib/iris/tests/unit/coord_systems/test_Orthographic.py b/lib/iris/tests/unit/coord_systems/test_Orthographic.py
index ae00f4e8c7..a7c5d49736 100644
--- a/lib/iris/tests/unit/coord_systems/test_Orthographic.py
+++ b/lib/iris/tests/unit/coord_systems/test_Orthographic.py
@@ -69,5 +69,32 @@ def test_projection_creation(self):
self.assertEqual(res, expected)
+class Test_init_defaults(tests.IrisTest):
+ # NOTE: most of the testing for Orthographic.__init__ is elsewhere.
+ # This class *only* tests the defaults for optional constructor args.
+
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = Orthographic(0, 0, false_easting=100, false_northing=-203.7)
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -203.7)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = Orthographic(0, 0)
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = Orthographic(0, 0, false_easting=None, false_northing=None)
+ self._check_crs_defaults(crs)
+
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_RotatedPole.py b/lib/iris/tests/unit/coord_systems/test_RotatedPole.py
index 3d99dbc13f..52fdaf02bd 100644
--- a/lib/iris/tests/unit/coord_systems/test_RotatedPole.py
+++ b/lib/iris/tests/unit/coord_systems/test_RotatedPole.py
@@ -62,6 +62,23 @@ def test_as_cartopy_projection(self):
sorted(expected.proj4_init.split(" +")),
)
+ def _check_crs_default(self, crs):
+ # Check for property defaults when no kwargs options are set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.north_pole_grid_longitude, 0.0)
+
+ def test_optional_args_missing(self):
+ # Check that unused 'north_pole_grid_longitude' defaults to 0.0.
+ crs = RotatedGeogCS(self.pole_lon, self.pole_lat)
+ self._check_crs_default(crs)
+
+ def test_optional_args_None(self):
+ # Check that 'north_pole_grid_longitude=None' defaults to 0.0.
+ crs = RotatedGeogCS(
+ self.pole_lon, self.pole_lat, north_pole_grid_longitude=None
+ )
+ self._check_crs_default(crs)
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_Stereographic.py b/lib/iris/tests/unit/coord_systems/test_Stereographic.py
new file mode 100644
index 0000000000..d505906e22
--- /dev/null
+++ b/lib/iris/tests/unit/coord_systems/test_Stereographic.py
@@ -0,0 +1,50 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""Unit tests for the :class:`iris.coord_systems.Stereographic` class."""
+
+# Import iris.tests first so that some things can be initialised before
+# importing anything else.
+import iris.tests as tests
+
+from iris.coord_systems import Stereographic
+
+
+class Test_init_defaults(tests.IrisTest):
+ # NOTE: most of the testing for Stereographic is in the legacy test module
+ # 'iris.tests.test_coordsystem'.
+ # This class *only* tests the defaults for optional constructor args.
+
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = Stereographic(
+ 0, 0, false_easting=100, false_northing=-203.7, true_scale_lat=77
+ )
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -203.7)
+ self.assertEqualAndKind(crs.true_scale_lat, 77.0)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+ self.assertIsNone(crs.true_scale_lat)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = Stereographic(0, 0)
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = Stereographic(
+ 0, 0, false_easting=None, false_northing=None, true_scale_lat=None
+ )
+ self._check_crs_defaults(crs)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_TransverseMercator.py b/lib/iris/tests/unit/coord_systems/test_TransverseMercator.py
new file mode 100644
index 0000000000..1d04463316
--- /dev/null
+++ b/lib/iris/tests/unit/coord_systems/test_TransverseMercator.py
@@ -0,0 +1,58 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""Unit tests for the :class:`iris.coord_systems.TransverseMercator` class."""
+
+# Import iris.tests first so that some things can be initialised before
+# importing anything else.
+import iris.tests as tests
+
+from iris.coord_systems import TransverseMercator
+
+
+class Test_init_defaults(tests.IrisTest):
+ # NOTE: most of the testing for TransverseMercator is in the legacy test
+ # module 'iris.tests.test_coordsystem'.
+ # This class *only* tests the defaults for optional constructor args.
+
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = TransverseMercator(
+ 0,
+ 50,
+ false_easting=100,
+ false_northing=-203.7,
+ scale_factor_at_central_meridian=1.057,
+ )
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -203.7)
+ self.assertEqualAndKind(crs.scale_factor_at_central_meridian, 1.057)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+ self.assertEqualAndKind(crs.scale_factor_at_central_meridian, 1.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = TransverseMercator(0, 50)
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = TransverseMercator(
+ 0,
+ 50,
+ false_easting=None,
+ false_northing=None,
+ scale_factor_at_central_meridian=None,
+ )
+ self._check_crs_defaults(crs)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/coord_systems/test_VerticalPerspective.py b/lib/iris/tests/unit/coord_systems/test_VerticalPerspective.py
index 63ad393c33..155579730e 100644
--- a/lib/iris/tests/unit/coord_systems/test_VerticalPerspective.py
+++ b/lib/iris/tests/unit/coord_systems/test_VerticalPerspective.py
@@ -57,6 +57,32 @@ def test_projection_creation(self):
res = self.vp_cs.as_cartopy_projection()
self.assertEqual(res, self.expected)
+ def test_set_optional_args(self):
+ # Check that setting the optional (non-ellipse) args works.
+ crs = VerticalPerspective(
+ 0, 0, 1000, false_easting=100, false_northing=-203.7
+ )
+ self.assertEqualAndKind(crs.false_easting, 100.0)
+ self.assertEqualAndKind(crs.false_northing, -203.7)
+
+ def _check_crs_defaults(self, crs):
+ # Check for property defaults when no kwargs options were set.
+ # NOTE: except ellipsoid, which is done elsewhere.
+ self.assertEqualAndKind(crs.false_easting, 0.0)
+ self.assertEqualAndKind(crs.false_northing, 0.0)
+
+ def test_no_optional_args(self):
+ # Check expected defaults with no optional args.
+ crs = VerticalPerspective(0, 0, 1000)
+ self._check_crs_defaults(crs)
+
+ def test_optional_args_None(self):
+ # Check expected defaults with optional args=None.
+ crs = VerticalPerspective(
+ 0, 0, 1000, false_easting=None, false_northing=None
+ )
+ self._check_crs_defaults(crs)
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_albers_equal_area_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_albers_equal_area_coordinate_system.py
new file mode 100644
index 0000000000..4d4f719714
--- /dev/null
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_albers_equal_area_coordinate_system.py
@@ -0,0 +1,88 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""
+Test function :func:`iris.fileformats._pyke_rules.compiled_krb.\
+fc_rules_cf_fc.build_albers_equal_area_coordinate_system`.
+
+"""
+
+# import iris tests first so that some things can be initialised before
+# importing anything else
+import iris.tests as tests
+
+from unittest import mock
+
+import iris
+from iris.coord_systems import AlbersEqualArea
+from iris.fileformats._pyke_rules.compiled_krb.fc_rules_cf_fc import \
+ build_albers_equal_area_coordinate_system
+
+
+class TestBuildAlbersEqualAreaCoordinateSystem(tests.IrisTest):
+ def _test(self, inverse_flattening=False, no_optionals=False):
+ if no_optionals:
+ # Most properties are optional for this system.
+ gridvar_props = {}
+ # Setup all the expected default values
+ test_lat = 0
+ test_lon = 0
+ test_easting = 0
+ test_northing = 0
+ test_parallels = (20, 50)
+ else:
+ # Choose test values and setup corresponding named properties.
+ test_lat = -35
+ test_lon = 175
+ test_easting = -100
+ test_northing = 200
+ test_parallels = (-27, 3)
+ gridvar_props = dict(
+ latitude_of_projection_origin=test_lat,
+ longitude_of_central_meridian=test_lon,
+ false_easting=test_easting,
+ false_northing=test_northing,
+ standard_parallel=test_parallels)
+
+ # Add ellipsoid args.
+ gridvar_props['semi_major_axis'] = 6377563.396
+ if inverse_flattening:
+ gridvar_props['inverse_flattening'] = 299.3249646
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396,
+ inverse_flattening=299.3249646)
+ else:
+ gridvar_props['semi_minor_axis'] = 6356256.909
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396, 6356256.909)
+
+ cf_grid_var = mock.Mock(spec=[], **gridvar_props)
+
+ cs = build_albers_equal_area_coordinate_system(None, cf_grid_var)
+
+ expected = AlbersEqualArea(
+ latitude_of_projection_origin=test_lat,
+ longitude_of_central_meridian=test_lon,
+ false_easting=test_easting,
+ false_northing=test_northing,
+ standard_parallels=test_parallels,
+ ellipsoid=expected_ellipsoid)
+
+ self.assertEqual(cs, expected)
+
+ def test_basic(self):
+ self._test()
+
+ def test_inverse_flattening(self):
+ # Check when inverse_flattening is provided instead of semi_minor_axis.
+ self._test(inverse_flattening=True)
+
+ def test_no_optionals(self):
+ # Check defaults, when all optional attributes are absent.
+ self._test(no_optionals=True)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_lambert_azimuthal_equal_area_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_lambert_azimuthal_equal_area_coordinate_system.py
new file mode 100644
index 0000000000..fd3aa189bf
--- /dev/null
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_lambert_azimuthal_equal_area_coordinate_system.py
@@ -0,0 +1,85 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""
+Test function :func:`iris.fileformats._pyke_rules.compiled_krb.\
+fc_rules_cf_fc.build_lambert_azimuthal_equal_area_coordinate_system`.
+
+"""
+
+# import iris tests first so that some things can be initialised before
+# importing anything else
+import iris.tests as tests
+
+from unittest import mock
+
+import iris
+from iris.coord_systems import LambertAzimuthalEqualArea
+from iris.fileformats._pyke_rules.compiled_krb.fc_rules_cf_fc import \
+ build_lambert_azimuthal_equal_area_coordinate_system
+
+
+class TestBuildLambertAzimuthalEqualAreaCoordinateSystem(tests.IrisTest):
+ def _test(self, inverse_flattening=False, no_optionals=False):
+ if no_optionals:
+ # Most properties are optional for this system.
+ gridvar_props = {}
+ # Setup all the expected default values
+ test_lat = 0
+ test_lon = 0
+ test_easting = 0
+ test_northing = 0
+ else:
+ # Choose test values and setup corresponding named properties.
+ test_lat = -35
+ test_lon = 175
+ test_easting = -100
+ test_northing = 200
+ gridvar_props = dict(
+ latitude_of_projection_origin=test_lat,
+ longitude_of_projection_origin=test_lon,
+ false_easting=test_easting,
+ false_northing=test_northing)
+
+ # Add ellipsoid args.
+ gridvar_props['semi_major_axis'] = 6377563.396
+ if inverse_flattening:
+ gridvar_props['inverse_flattening'] = 299.3249646
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396,
+ inverse_flattening=299.3249646)
+ else:
+ gridvar_props['semi_minor_axis'] = 6356256.909
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396, 6356256.909)
+
+ cf_grid_var = mock.Mock(spec=[], **gridvar_props)
+
+ cs = build_lambert_azimuthal_equal_area_coordinate_system(
+ None, cf_grid_var)
+
+ expected = LambertAzimuthalEqualArea(
+ latitude_of_projection_origin=test_lat,
+ longitude_of_projection_origin=test_lon,
+ false_easting=test_easting,
+ false_northing=test_northing,
+ ellipsoid=expected_ellipsoid)
+
+ self.assertEqual(cs, expected)
+
+ def test_basic(self):
+ self._test()
+
+ def test_inverse_flattening(self):
+ # Check when inverse_flattening is provided instead of semi_minor_axis.
+ self._test(inverse_flattening=True)
+
+ def test_no_optionals(self):
+ # Check defaults, when all optional attributes are absent.
+ self._test(no_optionals=True)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_lambert_conformal_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_lambert_conformal_coordinate_system.py
new file mode 100644
index 0000000000..f56b3d5f14
--- /dev/null
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_lambert_conformal_coordinate_system.py
@@ -0,0 +1,88 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""
+Test function :func:`iris.fileformats._pyke_rules.compiled_krb.\
+fc_rules_cf_fc.build_lambert_conformal_coordinate_system`.
+
+"""
+
+# import iris tests first so that some things can be initialised before
+# importing anything else
+import iris.tests as tests
+
+from unittest import mock
+
+import iris
+from iris.coord_systems import LambertConformal
+from iris.fileformats._pyke_rules.compiled_krb.fc_rules_cf_fc import \
+ build_lambert_conformal_coordinate_system
+
+
+class TestBuildLambertConformalCoordinateSystem(tests.IrisTest):
+ def _test(self, inverse_flattening=False, no_optionals=False):
+ if no_optionals:
+ # Most properties are optional in this case.
+ gridvar_props = {}
+ # Setup all the expected default values
+ test_lat = 39
+ test_lon = -96
+ test_easting = 0
+ test_northing = 0
+ test_parallels = (33, 45)
+ else:
+ # Choose test values and setup corresponding named properties.
+ test_lat = -35
+ test_lon = 175
+ test_easting = -100
+ test_northing = 200
+ test_parallels = (-27, 3)
+ gridvar_props = dict(
+ latitude_of_projection_origin=test_lat,
+ longitude_of_central_meridian=test_lon,
+ false_easting=test_easting,
+ false_northing=test_northing,
+ standard_parallel=test_parallels)
+
+ # Add ellipsoid args.
+ gridvar_props['semi_major_axis'] = 6377563.396
+ if inverse_flattening:
+ gridvar_props['inverse_flattening'] = 299.3249646
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396,
+ inverse_flattening=299.3249646)
+ else:
+ gridvar_props['semi_minor_axis'] = 6356256.909
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396, 6356256.909)
+
+ cf_grid_var = mock.Mock(spec=[], **gridvar_props)
+
+ cs = build_lambert_conformal_coordinate_system(None, cf_grid_var)
+
+ expected = LambertConformal(
+ central_lat=test_lat,
+ central_lon=test_lon,
+ false_easting=test_easting,
+ false_northing=test_northing,
+ secant_latitudes=test_parallels,
+ ellipsoid=expected_ellipsoid)
+
+ self.assertEqual(cs, expected)
+
+ def test_basic(self):
+ self._test()
+
+ def test_inverse_flattening(self):
+ # Check when inverse_flattening is provided instead of semi_minor_axis.
+ self._test(inverse_flattening=True)
+
+ def test_no_optionals(self):
+ # Check defaults, when all optional attributes are absent.
+ self._test(no_optionals=True)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_mercator_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_mercator_coordinate_system.py
index 665beb8747..f59db6ef91 100644
--- a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_mercator_coordinate_system.py
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_mercator_coordinate_system.py
@@ -56,6 +56,20 @@ def test_inverse_flattening(self):
inverse_flattening=cf_grid_var.inverse_flattening))
self.assertEqual(cs, expected)
+ def test_longitude_missing(self):
+ cf_grid_var = mock.Mock(
+ spec=[],
+ semi_major_axis=6377563.396,
+ inverse_flattening=299.3249646)
+
+ cs = build_mercator_coordinate_system(None, cf_grid_var)
+
+ expected = Mercator(
+ ellipsoid=iris.coord_systems.GeogCS(
+ cf_grid_var.semi_major_axis,
+ inverse_flattening=cf_grid_var.inverse_flattening))
+ self.assertEqual(cs, expected)
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_stereographic_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_stereographic_coordinate_system.py
index e95f286a8d..791a0d6014 100644
--- a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_stereographic_coordinate_system.py
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_stereographic_coordinate_system.py
@@ -22,52 +22,57 @@
class TestBuildStereographicCoordinateSystem(tests.IrisTest):
- def test_valid(self):
- cf_grid_var = mock.Mock(
- spec=[],
+ def _test(self, inverse_flattening=False, no_offsets=False):
+ test_easting = -100
+ test_northing = 200
+ gridvar_props = dict(
latitude_of_projection_origin=0,
longitude_of_projection_origin=0,
- false_easting=-100,
- false_northing=200,
+ false_easting=test_easting,
+ false_northing=test_northing,
scale_factor_at_projection_origin=1,
- semi_major_axis=6377563.396,
- semi_minor_axis=6356256.909)
+ semi_major_axis=6377563.396)
- cs = build_stereographic_coordinate_system(None, cf_grid_var)
+ if inverse_flattening:
+ gridvar_props['inverse_flattening'] = 299.3249646
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396,
+ inverse_flattening=299.3249646)
+ else:
+ gridvar_props['semi_minor_axis'] = 6356256.909
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396, 6356256.909)
- expected = Stereographic(
- central_lat=cf_grid_var.latitude_of_projection_origin,
- central_lon=cf_grid_var.longitude_of_projection_origin,
- false_easting=cf_grid_var.false_easting,
- false_northing=cf_grid_var.false_northing,
- ellipsoid=iris.coord_systems.GeogCS(
- cf_grid_var.semi_major_axis,
- cf_grid_var.semi_minor_axis))
- self.assertEqual(cs, expected)
+ if no_offsets:
+ del gridvar_props['false_easting']
+ del gridvar_props['false_northing']
+ test_easting = 0
+ test_northing = 0
- def test_inverse_flattening(self):
- cf_grid_var = mock.Mock(
- spec=[],
- latitude_of_projection_origin=0,
- longitude_of_projection_origin=0,
- false_easting=-100,
- false_northing=200,
- scale_factor_at_projection_origin=1,
- semi_major_axis=6377563.396,
- inverse_flattening=299.3249646)
+ cf_grid_var = mock.Mock(spec=[], **gridvar_props)
cs = build_stereographic_coordinate_system(None, cf_grid_var)
expected = Stereographic(
central_lat=cf_grid_var.latitude_of_projection_origin,
central_lon=cf_grid_var.longitude_of_projection_origin,
- false_easting=cf_grid_var.false_easting,
- false_northing=cf_grid_var.false_northing,
- ellipsoid=iris.coord_systems.GeogCS(
- cf_grid_var.semi_major_axis,
- inverse_flattening=cf_grid_var.inverse_flattening))
+ false_easting=test_easting,
+ false_northing=test_northing,
+ ellipsoid=expected_ellipsoid)
+
self.assertEqual(cs, expected)
+ def test_basic(self):
+ self._test()
+
+ def test_inverse_flattening(self):
+ # Check when inverse_flattening is provided instead of semi_minor_axis.
+ self._test(inverse_flattening=True)
+
+ def test_no_offsets(self):
+ # Check when false_easting/northing attributes are absent.
+ self._test(no_offsets=True)
+
if __name__ == "__main__":
tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_transverse_mercator_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_transverse_mercator_coordinate_system.py
new file mode 100644
index 0000000000..62e8996cd1
--- /dev/null
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_transverse_mercator_coordinate_system.py
@@ -0,0 +1,82 @@
+# Copyright Iris contributors
+#
+# This file is part of Iris and is released under the LGPL license.
+# See COPYING and COPYING.LESSER in the root of the repository for full
+# licensing details.
+"""
+Test function :func:`iris.fileformats._pyke_rules.compiled_krb.\
+fc_rules_cf_fc.build_transverse_mercator_coordinate_system`.
+
+"""
+
+# import iris tests first so that some things can be initialised before
+# importing anything else
+import iris.tests as tests
+
+from unittest import mock
+
+import iris
+from iris.coord_systems import TransverseMercator
+from iris.fileformats._pyke_rules.compiled_krb.fc_rules_cf_fc import \
+ build_transverse_mercator_coordinate_system
+
+
+class TestBuildTransverseMercatorCoordinateSystem(tests.IrisTest):
+ def _test(self, inverse_flattening=False, no_options=False):
+ test_easting = -100
+ test_northing = 200
+ test_scale_factor = 1.234
+ gridvar_props = dict(
+ latitude_of_projection_origin=35.3,
+ longitude_of_central_meridian=-75,
+ false_easting=test_easting,
+ false_northing=test_northing,
+ scale_factor_at_central_meridian=test_scale_factor,
+ semi_major_axis=6377563.396)
+
+ if inverse_flattening:
+ gridvar_props['inverse_flattening'] = 299.3249646
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396,
+ inverse_flattening=299.3249646)
+ else:
+ gridvar_props['semi_minor_axis'] = 6356256.909
+ expected_ellipsoid = iris.coord_systems.GeogCS(
+ 6377563.396, 6356256.909)
+
+ if no_options:
+ del gridvar_props['false_easting']
+ del gridvar_props['false_northing']
+ del gridvar_props['scale_factor_at_central_meridian']
+ test_easting = 0
+ test_northing = 0
+ test_scale_factor = 1.0
+
+ cf_grid_var = mock.Mock(spec=[], **gridvar_props)
+
+ cs = build_transverse_mercator_coordinate_system(None, cf_grid_var)
+
+ expected = TransverseMercator(
+ latitude_of_projection_origin=(
+ cf_grid_var.latitude_of_projection_origin),
+ longitude_of_central_meridian=(
+ cf_grid_var.longitude_of_central_meridian),
+ false_easting=test_easting,
+ false_northing=test_northing,
+ scale_factor_at_central_meridian=test_scale_factor,
+ ellipsoid=expected_ellipsoid)
+
+ self.assertEqual(cs, expected)
+
+ def test_basic(self):
+ self._test()
+
+ def test_inverse_flattening(self):
+ self._test(inverse_flattening=True)
+
+ def test_missing_optionals(self):
+ self._test(no_options=True)
+
+
+if __name__ == "__main__":
+ tests.main()
diff --git a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_verticalp_coordinate_system.py b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_verticalp_coordinate_system.py
index d06e93e0ab..090e95e1f3 100644
--- a/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_verticalp_coordinate_system.py
+++ b/lib/iris/tests/unit/fileformats/pyke_rules/compiled_krb/fc_rules_cf_fc/test_build_verticalp_coordinate_system.py
@@ -22,18 +22,20 @@
class TestBuildVerticalPerspectiveCoordinateSystem(tests.IrisTest):
- def _test(self, inverse_flattening=False):
+ def _test(self, inverse_flattening=False, no_offsets=False):
"""
Generic test that can check vertical perspective validity with or
- without inverse flattening.
+ without inverse flattening, and false_east/northing-s.
"""
+ test_easting = 100.0
+ test_northing = 200.0
cf_grid_var_kwargs = {
'spec': [],
'latitude_of_projection_origin': 1.0,
'longitude_of_projection_origin': 2.0,
'perspective_point_height': 2000000.0,
- 'false_easting': 100.0,
- 'false_northing': 200.0,
+ 'false_easting': test_easting,
+ 'false_northing': test_northing,
'semi_major_axis': 6377563.396}
ellipsoid_kwargs = {'semi_major_axis': 6377563.396}
@@ -43,6 +45,12 @@ def _test(self, inverse_flattening=False):
ellipsoid_kwargs['semi_minor_axis'] = 6356256.909
cf_grid_var_kwargs.update(ellipsoid_kwargs)
+ if no_offsets:
+ del cf_grid_var_kwargs['false_easting']
+ del cf_grid_var_kwargs['false_northing']
+ test_easting = 0
+ test_northing = 0
+
cf_grid_var = mock.Mock(**cf_grid_var_kwargs)
ellipsoid = iris.coord_systems.GeogCS(**ellipsoid_kwargs)
@@ -53,8 +61,8 @@ def _test(self, inverse_flattening=False):
longitude_of_projection_origin=cf_grid_var.
longitude_of_projection_origin,
perspective_point_height=cf_grid_var.perspective_point_height,
- false_easting=cf_grid_var.false_easting,
- false_northing=cf_grid_var.false_northing,
+ false_easting=test_easting,
+ false_northing=test_northing,
ellipsoid=ellipsoid)
self.assertEqual(cs, expected)
@@ -63,4 +71,13 @@ def test_valid(self):
self._test(inverse_flattening=False)
def test_inverse_flattening(self):
+ # Check when inverse_flattening is provided instead of semi_minor_axis.
self._test(inverse_flattening=True)
+
+ def test_no_offsets(self):
+ # Check when false_easting/northing attributes are absent.
+ self._test(no_offsets=True)
+
+
+if __name__ == "__main__":
+ tests.main()