Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Iris
[![Join the chat at https://gitter.im/SciTools/iris](https://badges.gitter.im/SciTools/iris.svg)](https://gitter.im/SciTools/iris?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://api.travis-ci.org/repositories/SciTools/iris.svg?branch=master)](https://travis-ci.org/SciTools/iris/branches)
[![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.51860.svg)](https://dx.doi.org/10.5281/zenodo.51860)
[![Documentation for master branch ](https://img.shields.io/badge/docs-master-blue.svg)](https://scitools-docs.github.io/iris/master/index.html)

(C) British Crown Copyright 2010 - 2017, Met Office

Expand Down
18 changes: 14 additions & 4 deletions lib/iris/coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,14 +521,24 @@ def copy(self, points=None, bounds=None):
raise ValueError('If bounds are specified, points must also be '
'specified')

new_coord = copy.deepcopy(self)
if points is not None:
# We do not perform a deepcopy when we supply new points so as to
# not unncessarily copy the old points.

# Create a temp-coord to manage deep copying of a small array.
temp_coord = copy.copy(self)
temp_coord.bounds = None
# note: DataManager cannot be None or DataManager(None) for
# a deepcopy operation.
temp_coord._points_dm = DataManager(np.array((1,)))
new_coord = copy.deepcopy(temp_coord)
del(temp_coord)
new_coord._points_dm = None
new_coord.points = points
# Regardless of whether bounds are provided as an argument, new
# points will result in new bounds, discarding those copied from
# self.
# new points will result in new bounds.
new_coord.bounds = bounds
else:
new_coord = copy.deepcopy(self)

return new_coord

Expand Down
27 changes: 25 additions & 2 deletions lib/iris/cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,27 @@ def __init__(self, data, standard_name=None, long_name=None,
for cell_measure, dims in cell_measures_and_dims:
self.add_cell_measure(cell_measure, dims)

# When True indexing may result in a view onto the original data array,
# to avoid unnecessary copying.
self._share_data = False

@property
def share_data(self):
"""
Share cube data when slicing/indexing cube if True.
Setting this flag to True will realise the data payload,
if it is lazy, as lazy data cannot currently be shared across cubes.
"""
return self._share_data

@share_data.setter
def share_data(self, value):
# If value is True: realise the data (if is hasn't already been) as
# sharing lazy data is not possible.
if value and self.has_lazy_data():
_ = self.data
self._share_data = bool(value)

@property
def metadata(self):
"""
Expand Down Expand Up @@ -2173,8 +2194,10 @@ def new_cell_measure_dims(cm_):
dimension_mapping, data = iris.util._slice_data_with_keys(
cube_data, keys)

# We don't want a view of the data, so take a copy of it.
data = deepcopy(data)
# We don't want a view of the data, so take a copy of it, unless
# self.share_data is True.
if not self.share_data:
data = deepcopy(data)

# We can turn a masked array into a normal array if it's full.
if ma.isMaskedArray(data):
Expand Down
49 changes: 49 additions & 0 deletions lib/iris/tests/unit/cube/test_Cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from itertools import permutations

import dask.array as da
import numpy as np
import numpy.ma as ma

Expand Down Expand Up @@ -66,6 +67,10 @@ def test_matrix(self):
self.assertEqual(type(cube.data), np.ndarray)
self.assertArrayEqual(cube.data, data)

def test_default_share_data(self):
cube = Cube(np.arange(1))
self.assertFalse(cube.share_data)


class Test_extract(tests.IrisTest):
def test_scalar_cube_exists(self):
Expand Down Expand Up @@ -1877,6 +1882,50 @@ def test_remove_cell_measure(self):
[[self.b_cell_measure, (0, 1)]])


class Test_share_data(tests.IrisTest):
def test_setter_lazy_data(self):
cube = Cube(da.from_array(np.arange(6).reshape(2, 3), chunks=6))
cube.share_data = True
self.assertFalse(cube.has_lazy_data())
self.assertTrue(cube._share_data)

def test_setter_realised_data(self):
cube = Cube(np.arange(6).reshape(2, 3))
cube.share_data = True
self.assertFalse(cube.has_lazy_data())
self.assertTrue(cube._share_data)


class Test___getitem__no_share_data(tests.IrisTest):
def test_lazy_array(self):
cube = Cube(da.from_array(np.arange(6).reshape(2, 3), chunks=6))
cube2 = cube[1:]
self.assertTrue(cube2.has_lazy_data())
cube.data
self.assertTrue(cube2.has_lazy_data())

def test_ndarray(self):
cube = Cube(np.arange(6).reshape(2, 3))
cube2 = cube[1:]
self.assertIsNot(cube.data.base, cube2.data.base)


class Test___getitem__share_data(tests.IrisTest):
def test_lazy_array(self):
cube = Cube(da.from_array(np.arange(6).reshape(2, 3), chunks=6))
cube.share_data = True
cube2 = cube[1:]
self.assertFalse(cube.has_lazy_data())
self.assertFalse(cube2.has_lazy_data())
self.assertIs(cube.data.base, cube2.data.base)

def test_ndarray(self):
cube = Cube(np.arange(6).reshape(2, 3))
cube.share_data = True
cube2 = cube[1:]
self.assertIs(cube.data.base, cube2.data.base)


class Test__getitem_CellMeasure(tests.IrisTest):
def setUp(self):
cube = Cube(np.arange(6).reshape(2, 3))
Expand Down