Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@
:mod:`iris.fileformats._structured_array_identification.ArrayStructure` class.

"""

# Import iris.tests first so that some things can be initialised before
# importing anything else.
import iris.tests as tests # isort:skip

import numpy as np
import pytest

from iris.fileformats._structured_array_identification import (
ArrayStructure,
_UnstructuredArrayException,
)
from iris.tests._shared_utils import assert_array_equal


def construct_nd(sub_array, sub_dim, shape):
Expand All @@ -28,145 +25,145 @@ def construct_nd(sub_array, sub_dim, shape):
return sub_array.reshape(sub_shape) * np.ones(shape)


class TestArrayStructure_from_array(tests.IrisTest):
class TestArrayStructure_from_array:
def struct_from_arr(self, nd_array):
return ArrayStructure.from_array(nd_array.flatten())

def test_1d_len_0(self):
a = np.arange(0)
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, a))
assert self.struct_from_arr(a) == ArrayStructure(1, a)

def test_1d_len_1(self):
a = np.arange(1)
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, a))
assert self.struct_from_arr(a) == ArrayStructure(1, a)

def test_1d(self):
a = np.array([-1, 3, 1, 2])
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, a))
assert self.struct_from_arr(a) == ArrayStructure(1, a)

def test_1d_ones(self):
a = np.ones(10)
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, [1]))
assert self.struct_from_arr(a) == ArrayStructure(1, [1])

def test_1d_range(self):
a = np.arange(6)
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, list(range(6))))
assert self.struct_from_arr(a) == ArrayStructure(1, list(range(6)))

def test_3d_ones(self):
a = np.ones([10, 2, 1])
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, [1]))
assert self.struct_from_arr(a) == ArrayStructure(1, [1])

def test_1d_over_2d_first_dim_manual(self):
sub = np.array([10, 10, 20, 20])
self.assertEqual(self.struct_from_arr(sub), ArrayStructure(2, [10, 20]))
assert self.struct_from_arr(sub) == ArrayStructure(2, [10, 20])

def test_3d_first_dimension(self):
flattened = np.array([1, 1, 1, 2, 2, 2])
self.assertEqual(
ArrayStructure.from_array(flattened), ArrayStructure(3, [1, 2])
)
assert ArrayStructure.from_array(flattened) == ArrayStructure(3, [1, 2])

def test_1d_over_2d_first_dim(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 0, (4, 2))
self.assertEqual(self.struct_from_arr(a), ArrayStructure(2, sub))
assert self.struct_from_arr(a) == ArrayStructure(2, sub)

def test_1d_over_2d_second_dim(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 1, (2, 4))
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, sub))
assert self.struct_from_arr(a) == ArrayStructure(1, sub)

def test_1d_over_3d_first_dim(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 0, (4, 2, 3))
self.assertEqual(self.struct_from_arr(a), ArrayStructure(6, sub))
assert self.struct_from_arr(a) == ArrayStructure(6, sub)

def test_1d_over_3d_second_dim(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 1, (2, 4, 3))
self.assertEqual(self.struct_from_arr(a), ArrayStructure(3, sub))
assert self.struct_from_arr(a) == ArrayStructure(3, sub)

def test_1d_over_3d_third_dim(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 2, (3, 2, 4))
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, sub))
assert self.struct_from_arr(a) == ArrayStructure(1, sub)

def test_irregular_3d(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 2, (3, 2, 4))
a[0, 0, 0] = 5
self.assertEqual(self.struct_from_arr(a), None)
assert self.struct_from_arr(a) is None

def test_repeated_3d(self):
sub = np.array([-1, 3, 1, 2])
a = construct_nd(sub, 2, (3, 2, 4))
a[:, 0, 0] = 1
self.assertEqual(self.struct_from_arr(a), None)
assert self.struct_from_arr(a) is None

def test_rolled_3d(self):
# Shift the 3D array on by one, making the array 1d.
sub = np.arange(4)
a = construct_nd(sub, 0, (4, 2, 3))
a = np.roll(a.flatten(), 1)
self.assertEqual(self.struct_from_arr(a), None)
assert self.struct_from_arr(a) is None

def test_len_1_3d(self):
# Setup a case which triggers an IndexError when identifying
# the stride, but the result should still be correct.
sub = np.arange(2)
a = construct_nd(sub, 1, (1, 1, 1))
self.assertEqual(self.struct_from_arr(a), ArrayStructure(1, sub))
assert self.struct_from_arr(a) == ArrayStructure(1, sub)

def test_not_an_array(self):
# Support lists as an argument.
self.assertEqual(
ArrayStructure.from_array([1, 2, 3]), ArrayStructure(1, [1, 2, 3])
)
assert ArrayStructure.from_array([1, 2, 3]) == ArrayStructure(1, [1, 2, 3])

def test_multi_dim_array(self):
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
ArrayStructure.from_array(np.arange(12).reshape(3, 4))


class nd_array_and_dims_cases:
class TestNdarrayAndDimsCases:
"""Defines the test functionality for nd_array_and_dims. This class
isn't actually the test case - see the C order and F order subclasses
for those.

"""

@pytest.fixture(params=["c", "f"], ids=["c_order", "f_order"], autouse=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pp-mo Nice 🎖️

def _order(self, request):
self.order = request.param

def test_scalar_len1_first_dim(self):
struct = ArrayStructure(1, [1])
orig = np.array([1, 1, 1])

array, dims = struct.nd_array_and_dims(orig, (1, 3), order=self.order)
self.assertArrayEqual(array, [1])
self.assertEqual(dims, ())
assert_array_equal(array, [1])
assert dims == ()

def test_scalar_non_len1_first_dim(self):
struct = ArrayStructure(1, [1])
orig = np.array([1, 1, 1])

array, dims = struct.nd_array_and_dims(orig, (3, 1), order=self.order)
self.assertArrayEqual(array, [1])
self.assertEqual(dims, ())
assert_array_equal(array, [1])
assert dims == ()

def test_single_vector(self):
orig = construct_nd(np.array([1, 2]), 0, (2, 1, 3))
flattened = orig.flatten(order=self.order)
struct = ArrayStructure.from_array(flattened)
array, dims = struct.nd_array_and_dims(flattened, (2, 1, 3), order=self.order)
self.assertArrayEqual(array, [1, 2])
self.assertEqual(dims, (0,))
assert_array_equal(array, [1, 2])
assert dims == (0,)

def test_single_vector_3rd_dim(self):
orig = construct_nd(np.array([1, 2, 3]), 2, (4, 1, 3))
flattened = orig.flatten(order=self.order)

struct = ArrayStructure.from_array(flattened)
array, dims = struct.nd_array_and_dims(flattened, (4, 1, 3), order=self.order)
self.assertArrayEqual(array, [1, 2, 3])
self.assertEqual(dims, (2,))
assert_array_equal(array, [1, 2, 3])
assert dims == (2,)

def test_orig_array_and_target_shape_inconsistent(self):
# An array structure which has a length which is a product
Expand All @@ -175,7 +172,7 @@ def test_orig_array_and_target_shape_inconsistent(self):
orig = np.array([1, 1, 2, 2, 3, 3])

msg = "Original array and target shape do not match up."
with self.assertRaisesRegex(ValueError, msg):
with pytest.raises(ValueError, match=msg):
struct.nd_array_and_dims(orig, (2, 3, 2), order=self.order)

def test_array_bigger_than_expected(self):
Expand All @@ -184,7 +181,7 @@ def test_array_bigger_than_expected(self):
struct = ArrayStructure(2, [1, 2, 3, 4, 5, 6])
orig = np.array([1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6])

with self.assertRaises(_UnstructuredArrayException):
with pytest.raises(_UnstructuredArrayException):
struct.nd_array_and_dims(orig, (2, 3, 2), order=self.order)

def test_single_vector_extra_dimension(self):
Expand All @@ -199,21 +196,5 @@ def test_single_vector_extra_dimension(self):
array, dims = struct.nd_array_and_dims(
input_array, (3, 1, 2, 1), order=self.order
)
self.assertArrayEqual(array, [[1, 101], [2, 102]])
self.assertEqual(dims, (2,))


class TestArrayStructure_nd_array_and_dims_f_order(
tests.IrisTest, nd_array_and_dims_cases
):
order = "f"


class TestArrayStructure_nd_array_and_dims_c_order(
tests.IrisTest, nd_array_and_dims_cases
):
order = "c"


if __name__ == "__main__":
tests.main()
assert_array_equal(array, [[1, 101], [2, 102]])
assert dims == (2,)
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
import iris.tests as tests # isort:skip

import numpy as np
import pytest

from iris.fileformats._structured_array_identification import (
ArrayStructure,
GroupStructure,
)
from iris.tests._shared_utils import assert_array_equal


def regular_array_structures(shape, names="abcdefg"):
Expand All @@ -34,7 +36,7 @@ class TestGroupStructure_from_component_arrays(tests.IrisTest):
def test_different_sizes(self):
arrays = {"a": np.arange(6), "b": np.arange(5)}
msg = "All array elements must have the same size."
with self.assertRaisesRegex(ValueError, msg):
with pytest.raises(ValueError, match=msg):
GroupStructure.from_component_arrays(arrays)

def test_structure_creation(self):
Expand All @@ -45,8 +47,8 @@ def test_structure_creation(self):

grp = GroupStructure.from_component_arrays({"a": array})

self.assertEqual(grp.length, 6)
self.assertEqual(grp._cmpt_structure, expected_structure)
assert grp.length == 6
assert grp._cmpt_structure == expected_structure


class TestGroupStructure_possible_structures(tests.IrisTest):
Expand All @@ -66,15 +68,15 @@ def test_simple_3d_structure(self):
("c", array_structures["c"]),
],
)
self.assertEqual(structure.possible_structures(), expected)
assert structure.possible_structures() == expected

def assert_potentials(self, length, array_structures, expected):
structure = GroupStructure(length, array_structures, array_order="f")
allowed = structure.possible_structures()
names = [
[name for (name, _) in allowed_structure] for allowed_structure in allowed
]
self.assertEqual(names, expected)
assert names == expected

def test_multiple_potentials(self):
# More than one potential dimension for dim 1.
Expand Down Expand Up @@ -116,8 +118,8 @@ class TestGroupStructure_build_arrays(tests.IrisTest):
def assert_built_array(self, name, result, expected):
ex_arr, ex_dims = expected
re_arr, re_dims = result[name]
self.assertEqual(ex_dims, re_dims)
self.assertArrayEqual(ex_arr, re_arr)
assert ex_dims == re_dims
assert_array_equal(ex_arr, re_arr)

def test_build_arrays_regular_f_order(self):
# Construct simple orthogonal 1d array structures, adding a trailing
Expand Down Expand Up @@ -181,7 +183,3 @@ def test_structured_array_not_applicable(self):
},
)
self.assert_built_array("d", r, (expected, (0, 1, 2)))


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