From 2fba628b27ec3b3687f42a6035be7a22464cdbe7 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Mon, 16 Nov 2015 16:40:19 +0000 Subject: [PATCH 1/4] lazy cube exponentiate --- lib/iris/analysis/maths.py | 6 +- .../unit/analysis/maths/test_exponentiate.py | 61 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 lib/iris/tests/unit/analysis/maths/test_exponentiate.py diff --git a/lib/iris/analysis/maths.py b/lib/iris/analysis/maths.py index 223432e076..affac3ebab 100644 --- a/lib/iris/analysis/maths.py +++ b/lib/iris/analysis/maths.py @@ -386,8 +386,8 @@ def exponentiate(cube, exponent, in_place=False): """ _assert_is_cube(cube) - def power(data, out=None): - return np.power(data, exponent, out) + def power(data): + return np.power(data, exponent) return _math_op_common(cube, power, cube.units ** exponent, in_place=in_place) @@ -660,7 +660,7 @@ def _math_op_common(cube, operation_function, new_unit, in_place=False): operation_function(new_cube._my_data, out=new_cube._my_data) except TypeError: # Non ufunc function - operation_function(new_cube.data) + operation_function(new_cube._my_data) else: new_cube = cube.copy(data=operation_function(cube._my_data)) iris.analysis.clear_phenomenon_identity(new_cube) diff --git a/lib/iris/tests/unit/analysis/maths/test_exponentiate.py b/lib/iris/tests/unit/analysis/maths/test_exponentiate.py new file mode 100644 index 0000000000..a43b68c72a --- /dev/null +++ b/lib/iris/tests/unit/analysis/maths/test_exponentiate.py @@ -0,0 +1,61 @@ +# (C) British Crown Copyright 2015, Met Office +# +# This file is part of Iris. +# +# Iris is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Iris. If not, see . +"""Unit tests for the :func:`iris.analysis.maths.exponentiate` function.""" + +from __future__ import (absolute_import, division, print_function) +from six.moves import (filter, input, map, range, zip) # noqa + +# Import iris.tests first so that some things can be initialised before +# importing anything else. +import iris.tests as tests +from iris.tests.stock import simple_2d + +import iris +from iris.analysis.maths import exponentiate +import numpy as np + + +class Test_exponentiate(tests.IrisTest): + def setUp(self): + self.cube = simple_2d(with_bounds=False) + self.exponent = 2 + self.expected = self.cube.data ** self.exponent + + def test_basic(self): + result = exponentiate(self.cube, self.exponent) + self.assertArrayEqual(result.data, self.expected) + + def test_masked(self): + cube = self.cube.copy() + mask = cube.data % 3 == 0 + masked_data = np.ma.masked_array(cube.data, mask) + cube.data = masked_data + expected = masked_data ** 2 + result = exponentiate(cube, self.exponent) + self.assertMaskedArrayEqual(result.data, expected) + + @tests.skip_data + def test_lazy_data(self): + # Confirm that the cube's lazy data is preserved through the operation. + test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) + cube = iris.load_cube(test_data) + exponentiate(cube, self.exponent, in_place=True) + self.assertTrue(cube.has_lazy_data()) + + +if __name__ == "__main__": + tests.main() From c551b11024104a68b95c0df983c3b0b54013a731 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Fri, 20 Nov 2015 16:29:18 +0000 Subject: [PATCH 2/4] Review actions --- lib/iris/analysis/maths.py | 8 +--- .../unit/analysis/maths/test_exponentiate.py | 42 ++++++++++++++++--- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/lib/iris/analysis/maths.py b/lib/iris/analysis/maths.py index affac3ebab..dbb8b506d1 100644 --- a/lib/iris/analysis/maths.py +++ b/lib/iris/analysis/maths.py @@ -387,7 +387,7 @@ def exponentiate(cube, exponent, in_place=False): _assert_is_cube(cube) def power(data): - return np.power(data, exponent) + return biggus.power(data, exponent) return _math_op_common(cube, power, cube.units ** exponent, in_place=in_place) @@ -656,11 +656,7 @@ def _math_op_common(cube, operation_function, new_unit, in_place=False): _assert_is_cube(cube) if in_place: new_cube = cube - try: - operation_function(new_cube._my_data, out=new_cube._my_data) - except TypeError: - # Non ufunc function - operation_function(new_cube._my_data) + new_cube._my_data = operation_function(new_cube._my_data) else: new_cube = cube.copy(data=operation_function(cube._my_data)) iris.analysis.clear_phenomenon_identity(new_cube) diff --git a/lib/iris/tests/unit/analysis/maths/test_exponentiate.py b/lib/iris/tests/unit/analysis/maths/test_exponentiate.py index a43b68c72a..2e9583d740 100644 --- a/lib/iris/tests/unit/analysis/maths/test_exponentiate.py +++ b/lib/iris/tests/unit/analysis/maths/test_exponentiate.py @@ -32,12 +32,12 @@ class Test_exponentiate(tests.IrisTest): def setUp(self): self.cube = simple_2d(with_bounds=False) - self.exponent = 2 - self.expected = self.cube.data ** self.exponent + self.exponent = np.float32(2) def test_basic(self): + expected = self.cube.data ** self.exponent result = exponentiate(self.cube, self.exponent) - self.assertArrayEqual(result.data, self.expected) + self.assertArrayEqual(result.data, expected) def test_masked(self): cube = self.cube.copy() @@ -49,12 +49,44 @@ def test_masked(self): self.assertMaskedArrayEqual(result.data, expected) @tests.skip_data - def test_lazy_data(self): - # Confirm that the cube's lazy data is preserved through the operation. + def test_lazy_data__inplace(self): + # Confirm that the cube's lazy data is preserved through an operation + # that is not in-place. test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) cube = iris.load_cube(test_data) + expected = cube.copy().data ** self.exponent exponentiate(cube, self.exponent, in_place=True) self.assertTrue(cube.has_lazy_data()) + self.assertArrayAlmostEqual(cube.data, expected) + + @tests.skip_data + def test_lazy_data__not_inplace(self): + # Confirm that the cube's lazy data is preserved through an + # in-place operation. + test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) + cube = iris.load_cube(test_data) + expected = cube.copy().data ** self.exponent + result = exponentiate(cube, self.exponent, in_place=False) + self.assertTrue(result.has_lazy_data()) + self.assertArrayEqual(result.data, expected) + + @tests.skip_data + def test_exponentiate__preloaded_data__inplace(self): + test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) + cube = iris.load_cube(test_data) + expected = cube.data ** self.exponent + exponentiate(cube, self.exponent, in_place=True) + self.assertTrue(cube.has_lazy_data()) + self.assertArrayAlmostEqual(cube.data, expected) + + @tests.skip_data + def test_exponentiate__preloaded_data__not_inplace(self): + test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) + cube = iris.load_cube(test_data) + expected = cube.data ** self.exponent + result = exponentiate(cube, self.exponent, in_place=False) + self.assertTrue(result.has_lazy_data()) + self.assertArrayAlmostEqual(result.data, expected) if __name__ == "__main__": From 755b305b9af25569634ace21929e08f9ab52ac8b Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Mon, 23 Nov 2015 12:22:27 +0000 Subject: [PATCH 3/4] Remove reliance on real data from tests --- .../unit/analysis/maths/test_exponentiate.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/iris/tests/unit/analysis/maths/test_exponentiate.py b/lib/iris/tests/unit/analysis/maths/test_exponentiate.py index 2e9583d740..98aa7ef228 100644 --- a/lib/iris/tests/unit/analysis/maths/test_exponentiate.py +++ b/lib/iris/tests/unit/analysis/maths/test_exponentiate.py @@ -24,6 +24,7 @@ import iris.tests as tests from iris.tests.stock import simple_2d +from biggus import NumpyArrayAdapter import iris from iris.analysis.maths import exponentiate import numpy as np @@ -48,41 +49,41 @@ def test_masked(self): result = exponentiate(cube, self.exponent) self.assertMaskedArrayEqual(result.data, expected) - @tests.skip_data def test_lazy_data__inplace(self): # Confirm that the cube's lazy data is preserved through an operation # that is not in-place. - test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) - cube = iris.load_cube(test_data) + cube = self.cube.copy() + cube.lazy_data(array=NumpyArrayAdapter(cube.data)) expected = cube.copy().data ** self.exponent exponentiate(cube, self.exponent, in_place=True) self.assertTrue(cube.has_lazy_data()) self.assertArrayAlmostEqual(cube.data, expected) - @tests.skip_data def test_lazy_data__not_inplace(self): # Confirm that the cube's lazy data is preserved through an # in-place operation. - test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) - cube = iris.load_cube(test_data) + cube = self.cube.copy() + cube.lazy_data(array=NumpyArrayAdapter(cube.data)) expected = cube.copy().data ** self.exponent result = exponentiate(cube, self.exponent, in_place=False) self.assertTrue(result.has_lazy_data()) self.assertArrayEqual(result.data, expected) - @tests.skip_data def test_exponentiate__preloaded_data__inplace(self): - test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) - cube = iris.load_cube(test_data) + # Confirm that the cube's data is lazy after an in-place operation and + # after pre-loading the data. + cube = self.cube.copy() + cube.lazy_data(array=NumpyArrayAdapter(cube.data)) expected = cube.data ** self.exponent exponentiate(cube, self.exponent, in_place=True) self.assertTrue(cube.has_lazy_data()) self.assertArrayAlmostEqual(cube.data, expected) - @tests.skip_data def test_exponentiate__preloaded_data__not_inplace(self): - test_data = tests.get_data_path(('PP', 'simple_pp', 'global.pp')) - cube = iris.load_cube(test_data) + # Confirm that the cube's data is lazy after an operation that is not + # in-place and after pre-loading the data. + cube = self.cube.copy() + cube.lazy_data(array=NumpyArrayAdapter(cube.data)) expected = cube.data ** self.exponent result = exponentiate(cube, self.exponent, in_place=False) self.assertTrue(result.has_lazy_data()) From 584574d13086839f14a47fbbeeeae4533dd47b19 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Thu, 21 Jan 2016 12:11:18 +0000 Subject: [PATCH 4/4] TMP: test change --- lib/iris/tests/test_basic_maths.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/iris/tests/test_basic_maths.py b/lib/iris/tests/test_basic_maths.py index e690805140..8ce0eefa12 100644 --- a/lib/iris/tests/test_basic_maths.py +++ b/lib/iris/tests/test_basic_maths.py @@ -562,10 +562,10 @@ def vec_mag(u, v): vec_mag_ufunc = np.frompyfunc(vec_mag, 2, 1) b = iris.analysis.maths.apply_ufunc(vec_mag_ufunc, a, c) - ans = a.data**2 + c.data**2 - b2 = b**2 + ans = np.sqrt(a.data**2 + c.data**2) + # b2 = b**2 - self.assertArrayAlmostEqual(b2.data, ans) + self.assertArrayAlmostEqual(b.data, ans) class TestIFunc(tests.IrisTest): def setUp(self):