Skip to content
6 changes: 3 additions & 3 deletions lib/iris/aux_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ def _dependency_dims(self, coord_dims_func):
dependency_dims[key] = coord_dims_func(coord)
return dependency_dims

def _nd_bounds(self, coord, dims, ndim):
@staticmethod
def _nd_bounds(coord, dims, ndim):
"""
Returns the coord's bounds in Cube-orientation and
broadcastable to N dimensions.
Expand All @@ -187,7 +188,7 @@ def _nd_bounds(self, coord, dims, ndim):
# Transpose to be consistent with the Cube.
sorted_pairs = sorted(enumerate(dims), key=lambda pair: pair[1])
transpose_order = [pair[0] for pair in sorted_pairs] + [len(dims)]
bounds = coord.bounds
bounds = coord.core_bounds()
if dims:
bounds = bounds.transpose(transpose_order)

Expand Down Expand Up @@ -296,7 +297,6 @@ def _remap_with_bounds(self, dependency_dims, derived_dims):
# extra dimension to make the shape compatible, so
# we just add an extra 1.
shape.append(1)
nd_values = np.array(nd_values)
nd_values = nd_values.reshape(shape)
else:
# If no coord, treat value as zero.
Expand Down
119 changes: 107 additions & 12 deletions lib/iris/tests/unit/aux_factory/test_AuxCoordFactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,48 @@
# importing anything else.
import iris.tests as tests

from iris._lazy_data import as_lazy_data, is_lazy_data
import numpy as np

import iris.coords
import iris
from iris._lazy_data import as_lazy_data, is_lazy_data
from iris.aux_factory import AuxCoordFactory
from iris.coords import AuxCoord


class Test__nd_points(tests.IrisTest):
def test_numpy_scalar_cooord(self):
points = np.arange(1)
coord = iris.coords.AuxCoord(points)
def test_numpy_scalar_coord__zero_ndim(self):
points = np.array(1)
coord = AuxCoord(points)
result = AuxCoordFactory._nd_points(coord, (), 0)
expected = np.array([1])
self.assertArrayEqual(result, expected)

def test_numpy_scalar_coord(self):
value = 1
points = np.array(value)
coord = AuxCoord(points)
result = AuxCoordFactory._nd_points(coord, (), 2)
expected = points[np.newaxis]
expected = np.array(value).reshape(1, 1)
self.assertArrayEqual(result, expected)

def test_numpy_simple(self):
points = np.arange(12).reshape(4, 3)
coord = iris.coords.AuxCoord(points)
coord = AuxCoord(points)
result = AuxCoordFactory._nd_points(coord, (0, 1), 2)
expected = points
self.assertArrayEqual(result, expected)

def test_numpy_complex(self):
points = np.arange(12).reshape(4, 3)
coord = iris.coords.AuxCoord(points)
coord = AuxCoord(points)
result = AuxCoordFactory._nd_points(coord, (3, 2), 5)
expected = points.T[np.newaxis, np.newaxis, ..., np.newaxis]
self.assertArrayEqual(result, expected)

def test_lazy_simple(self):
raw_points = np.arange(12).reshape(4, 3)
points = as_lazy_data(raw_points, 1)
coord = iris.coords.AuxCoord(points)
points = as_lazy_data(raw_points, raw_points.shape)
coord = AuxCoord(points)
self.assertTrue(is_lazy_data(coord.core_points()))
result = AuxCoordFactory._nd_points(coord, (0, 1), 2)
# Check we haven't triggered the loading of the coordinate values.
Expand All @@ -69,8 +78,8 @@ def test_lazy_simple(self):

def test_lazy_complex(self):
raw_points = np.arange(12).reshape(4, 3)
points = as_lazy_data(raw_points, 1)
coord = iris.coords.AuxCoord(points)
points = as_lazy_data(raw_points, raw_points.shape)
coord = AuxCoord(points)
self.assertTrue(is_lazy_data(coord.core_points()))
result = AuxCoordFactory._nd_points(coord, (3, 2), 5)
# Check we haven't triggered the loading of the coordinate values.
Expand All @@ -80,5 +89,91 @@ def test_lazy_complex(self):
self.assertArrayEqual(result, expected)


class Test__nd_bounds(tests.IrisTest):
def test_numpy_scalar_coord__zero_ndim(self):
points = np.array(0.5)
bounds = np.arange(2)
coord = AuxCoord(points, bounds=bounds)
result = AuxCoordFactory._nd_bounds(coord, (), 0)
expected = bounds
self.assertArrayEqual(result, expected)

def test_numpy_scalar_coord(self):
points = np.array(0.5)
bounds = np.arange(2).reshape(1, 2)
coord = AuxCoord(points, bounds=bounds)
result = AuxCoordFactory._nd_bounds(coord, (), 2)
expected = bounds[np.newaxis]
self.assertArrayEqual(result, expected)

def test_numpy_simple(self):
points = np.arange(12).reshape(4, 3)
bounds = np.arange(24).reshape(4, 3, 2)
coord = AuxCoord(points, bounds=bounds)
result = AuxCoordFactory._nd_bounds(coord, (0, 1), 2)
expected = bounds
self.assertArrayEqual(result, expected)

def test_numpy_complex(self):
points = np.arange(12).reshape(4, 3)
bounds = np.arange(24).reshape(4, 3, 2)
coord = AuxCoord(points, bounds=bounds)
result = AuxCoordFactory._nd_bounds(coord, (3, 2), 5)
expected = bounds.transpose((1, 0, 2)).reshape(1, 1, 3, 4, 1, 2)
self.assertArrayEqual(result, expected)

def test_lazy_simple(self):
raw_points = np.arange(12).reshape(4, 3)
points = as_lazy_data(raw_points, raw_points.shape)
raw_bounds = np.arange(24).reshape(4, 3, 2)
bounds = as_lazy_data(raw_bounds, raw_bounds.shape)
coord = AuxCoord(points, bounds=bounds)
self.assertTrue(is_lazy_data(coord.core_bounds()))
result = AuxCoordFactory._nd_bounds(coord, (0, 1), 2)
# Check we haven't triggered the loading of the coordinate values.
self.assertTrue(is_lazy_data(coord.core_bounds()))
self.assertTrue(is_lazy_data(result))
expected = raw_bounds
self.assertArrayEqual(result, expected)

def test_lazy_complex(self):
raw_points = np.arange(12).reshape(4, 3)
points = as_lazy_data(raw_points, raw_points.shape)
raw_bounds = np.arange(24).reshape(4, 3, 2)
bounds = as_lazy_data(raw_bounds, raw_bounds.shape)
coord = AuxCoord(points, bounds=bounds)
self.assertTrue(is_lazy_data(coord.core_bounds()))
result = AuxCoordFactory._nd_bounds(coord, (3, 2), 5)
# Check we haven't triggered the loading of the coordinate values.
self.assertTrue(is_lazy_data(coord.core_bounds()))
self.assertTrue(is_lazy_data(result))
expected = raw_bounds.transpose((1, 0, 2)).reshape(1, 1, 3, 4, 1, 2)
self.assertArrayEqual(result, expected)


@tests.skip_data
class Test_lazy_aux_coords(tests.IrisTest):
def setUp(self):
self.cube = iris.load_cube(tests.get_data_path
(['NetCDF', 'testing',
'small_theta_colpex.nc']))
self.coords = self.cube.aux_coords + self.cube.derived_coords

def _check_lazy(self):
for coord in self.coords:
self.assertTrue(coord.has_lazy_points())
if coord.has_bounds():
self.assertTrue(coord.has_lazy_bounds())

def test_lazy_coord_loading(self):
# Test that points and bounds arrays stay lazy upon cube loading.
self._check_lazy()

def test_lazy_coord_printing(self):
# Test that points and bounds arrays stay lazy after cube printing.
_ = str(self.cube)
self._check_lazy()


if __name__ == '__main__':
tests.main()