-
Couldn't load subscription status.
- Fork 297
Merge dataless #6741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
pp-mo
wants to merge
16
commits into
SciTools:main
Choose a base branch
from
pp-mo:merge_dataless
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Merge dataless #6741
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
c8fa1b4
Initial WIP for dataless merges -- cannot yet merge datafull+dataless.
pp-mo c4165a9
Starting tests.
pp-mo 4715ad5
Functioning backstop: merge can pass-through dataless, but not actual…
pp-mo 222acb5
Dataless merge, combine dataless with/without dataful.
pp-mo b1be959
Tidy awkward layout in test.
pp-mo 37fc7f5
Ensure that cube.shape can only be a tuple (or None).
pp-mo 6b0087c
Make test_merge check against dataless input in all its tests.
pp-mo 46ccc67
Improve tests, and test for lazy merge result.
pp-mo 1c4f14c
Fix typo.
pp-mo e3eec6f
Expand documentation.
pp-mo e0c2cd8
Fix broken ref + tweak whatsnew.
pp-mo 4f9da22
Merge branch 'main' into merge_dataless
pp-mo c2bfca5
Merge branch 'main' into merge_dataless
pp-mo 1cb44e7
Fixes following implementation of dataless save-and-load (#6739).
pp-mo f2c1f30
Remove redundant checks.
pp-mo 43d02ef
Make make_gridcube() dataless, and improve documentation cross-refs.
pp-mo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| .. _dataless-cubes: | ||
|
|
||
| ============== | ||
| Dataless Cubes | ||
| ============== | ||
| It is possible for a cube to exist without a data payload. | ||
| In this case ``cube.data`` is ``None``, instead of containing an array (real or lazy) as | ||
| usual. | ||
|
|
||
| This can be useful when the cube is used purely as a placeholder for metadata, e.g. to | ||
| represent a combination of coordinates. | ||
|
|
||
| Most notably, dataless cubes can be used as the target "grid cube" for most regridding | ||
| schemes, since in that case the cube's coordinates are all that the method uses. | ||
| See also :meth:`iris.util.make_gridcube`. | ||
|
|
||
|
|
||
| Properties of dataless cubes | ||
| ---------------------------- | ||
|
|
||
| * ``cube.shape`` is unchanged | ||
| * ``cube.data`` == ``None`` | ||
| * ``cube.dtype`` == ``None`` | ||
| * ``cube.core_data()`` == ``cube.lazy_data()`` == ``None`` | ||
| * ``cube.is_dataless()`` == ``True`` | ||
| * ``cube.has_lazy_data()`` == ``False`` | ||
|
|
||
|
|
||
| Cube creation | ||
| ------------- | ||
| You can create a dataless cube with the :meth:`~iris.cube.Cube` constructor | ||
| (i.e. ``__init__`` call), by specifying the ``shape`` keyword in place of ``data``. | ||
| If both are specified, an error is raised (even if data and shape are compatible). | ||
|
|
||
|
|
||
| Data assignment | ||
| --------------- | ||
| You can make an existing cube dataless, by setting ``cube.data = None``. | ||
| The data array is simply discarded. | ||
|
|
||
| Likewise, you can add data by assigning any data array of the correct shape, which | ||
| turns it into a 'normal' cube. | ||
|
|
||
| Note that ``cube.dtype`` always matches ``cube.data.dtype``. A dataless cube has a | ||
| dtype of ``None``. | ||
|
|
||
|
|
||
| Cube copy | ||
| --------- | ||
| The syntax that allows you to replace data on copying, | ||
| e.g. ``cube2 = cube.copy(new_data)``, has been extended to accept the special value | ||
| :data:`iris.DATALESS`. | ||
|
|
||
| So, ``cube2 = cube.copy(iris.DATALESS)`` makes ``cube2`` a | ||
| dataless copy of ``cube``. | ||
| This is equivalent to ``cube2 = cube.copy(); cube2.data = None``. | ||
|
|
||
|
|
||
| Save and Load | ||
| ------------- | ||
| The netcdf file interface can save and re-load dataless cubes correctly. | ||
| See: :ref:`save_load_dataless`. | ||
|
|
||
| .. _dataless_merge: | ||
|
|
||
| Merging | ||
| ------- | ||
| Merging is fully supported for dataless cubes, including combining them with "normal" | ||
| cubes. | ||
|
|
||
| * in all cases, the result has the same shape and metadata as if the same cubes had | ||
| data. | ||
| * Merging multiple dataless cubes produces a dataless result. | ||
| * Merging dataless and non-dataless cubes results in a partially 'missing' data array, | ||
| i.e. the relevant sections are filled with masked data. | ||
| * Laziness is also preserved. | ||
|
|
||
|
|
||
| Operations NOT supported | ||
| ------------------------- | ||
| Dataless cubes are relatively new, and only partly integrated with Iris cube operations | ||
| generally. | ||
|
|
||
| The following are some of the notable features which do *not* support dataless cubes, | ||
| at least as yet : | ||
|
|
||
| * plotting | ||
|
|
||
| * cube arithmetic | ||
|
|
||
| * statistics | ||
|
|
||
| * concatenation | ||
ukmo-ccbunney marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| * :meth:`iris.cube.CubeList.realise_data` | ||
|
|
||
| * various :class:`~iris.cube.Cube` methods, including at least: | ||
|
|
||
| * :meth:`~iris.cube.Cube.convert_units` | ||
|
|
||
| * :meth:`~iris.cube.Cube.subset` | ||
|
|
||
| * :meth:`~iris.cube.Cube.intersection` | ||
|
|
||
| * :meth:`~iris.cube.Cube.slices` | ||
|
|
||
| * :meth:`~iris.cube.Cube.interpolate` | ||
|
|
||
| * :meth:`~iris.cube.Cube.regrid` | ||
| Note: in this case the target ``grid`` can be dataless, but not the source | ||
| (``self``) cube. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # Copyright Iris contributors | ||
| # | ||
| # This file is part of Iris and is released under the BSD license. | ||
| # See LICENSE in the root of the repository for full licensing details. | ||
| """Integration tests for merging with dataless cubes.""" | ||
|
|
||
| import dask.array as da | ||
| import numpy as np | ||
|
|
||
| from iris.coords import AuxCoord, DimCoord | ||
| from iris.cube import Cube, CubeList | ||
|
|
||
|
|
||
| class TestMergeDataless: | ||
| def _testcube(self, z=1, name="this", dataless=False, lazy=False): | ||
| # Create a testcube with a scalar Z coord, for merge testing. | ||
| data = da.arange(3) if lazy else np.arange(3) | ||
| cube = Cube( | ||
| data, | ||
| long_name=name, | ||
| dim_coords_and_dims=[(DimCoord([0.0, 1.0, 2], long_name="x"), 0)], | ||
| aux_coords_and_dims=[(AuxCoord([z], long_name="z"), ())], | ||
| ) | ||
| if dataless: | ||
| cube.data = None | ||
| return cube | ||
|
|
||
| def test_mixed_passthrough(self): | ||
| # Check that normal merge can handle dataless alongside dataful cubes. | ||
| cube_normal = self._testcube(name="this", dataless=False) | ||
| cube_dataless = self._testcube(name="that", dataless=True) | ||
| cubes = CubeList([cube_normal, cube_dataless]) | ||
|
|
||
| result = cubes.merge() | ||
|
|
||
| assert len(result) == 2 | ||
| cube1, cube2 = [result.extract_cube(name) for name in ("this", "that")] | ||
| assert not cube1.is_dataless() | ||
| assert cube2.is_dataless() | ||
|
|
||
| def test_dataless_merge(self): | ||
| # Check that dataless cubes can be merged. | ||
| cube_1 = self._testcube(z=1, dataless=True) | ||
| cube_2 = self._testcube(z=2, dataless=True) | ||
| cubes = CubeList([cube_1, cube_2]) | ||
|
|
||
| cube = cubes.merge_cube() | ||
|
|
||
| assert cube.is_dataless() | ||
| assert np.all(cube.coord("z").points == [1, 2]) | ||
|
|
||
| def test_dataless_dataful_merge(self): | ||
| # Check that dataless cubes can merge **with** regular ones. | ||
| # Include checking that laziness is preserved. | ||
| cube_normal = self._testcube(z=1, dataless=False, lazy=True) | ||
| cube_dataless = self._testcube(z=2, dataless=True) | ||
| cubes = CubeList([cube_normal, cube_dataless]) | ||
|
|
||
| cube = cubes.merge_cube() | ||
|
|
||
| assert not cube.is_dataless() | ||
| assert cube.has_lazy_data() | ||
| data_z1, data_z2 = cube[0].data, cube[1].data | ||
| assert np.all(data_z1 == [0, 1, 2]) | ||
| assert np.all(np.ma.getmaskarray(data_z2) == True) # noqa: E712 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implication seems to be that
make_gridcubeshould be able to return dataless cubes, this doesn't look like part of this PR, is there a plan to implement this? If not, it might be worth clarifying what is relevant here aboutmake_gridcube.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry you are quite right.
I have dithered over whether to make that change in this PR, or not, and then sort-of forgot about it.
On reflection, I still think it's a useful enhancement, and I note that, since we haven't released it yet, I think it's OK to just make gridcubes dataless by default .
So I've now added this change.
If you can see a potential problem with this, it can be taken out again + considered separately.