Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
ce39fd5
dev
davidhassell Nov 7, 2024
3712766
dev
davidhassell Nov 7, 2024
fc0564e
dev
davidhassell Nov 8, 2024
bf07d57
dev
davidhassell Nov 8, 2024
68a61c7
dev
davidhassell Nov 8, 2024
df5d574
dev
davidhassell Nov 9, 2024
5a32001
dev
davidhassell Nov 11, 2024
5932aea
dev
davidhassell Nov 12, 2024
b4bd7c2
dev
davidhassell Nov 13, 2024
2bd687a
dev
davidhassell Nov 14, 2024
eb3f63f
dev
davidhassell Nov 15, 2024
acefc45
dev
davidhassell Nov 16, 2024
c594c75
dev
davidhassell Nov 17, 2024
e7cac6d
dev
davidhassell Nov 18, 2024
f2675af
dev
davidhassell Nov 19, 2024
88ab94a
dev
davidhassell Nov 19, 2024
6f5d08f
dev
davidhassell Nov 20, 2024
ed664b9
dev
davidhassell Nov 20, 2024
73f03b8
dev
davidhassell Nov 21, 2024
5c0c98e
dev
davidhassell Nov 22, 2024
03444d0
dev
davidhassell Nov 22, 2024
60e6ea0
dev
davidhassell Nov 22, 2024
b7e0937
dev
davidhassell Nov 22, 2024
4a26930
dev
davidhassell Nov 23, 2024
847d946
dev
davidhassell Nov 25, 2024
b86a529
dev
davidhassell Nov 25, 2024
26e2574
dev
davidhassell Nov 25, 2024
bb27a98
dev
davidhassell Nov 28, 2024
ad2e0d0
dev
davidhassell Nov 29, 2024
2b6e171
dev
davidhassell Nov 30, 2024
6545ae0
dev
davidhassell Dec 1, 2024
e2fac2c
dev
davidhassell Dec 2, 2024
dc67161
dev
davidhassell Dec 3, 2024
bff3583
dev
davidhassell Dec 4, 2024
65bb9f9
dev
davidhassell Dec 4, 2024
fea47c0
dev
davidhassell Dec 4, 2024
53b10f2
dev
davidhassell Dec 4, 2024
7dac03f
Merge branch 'dask-in-cfdm' into cfa-in-cfdm
davidhassell Dec 6, 2024
5a7da0f
dev
davidhassell Dec 6, 2024
3ecd63c
dev
davidhassell Dec 7, 2024
d6870d9
dev
davidhassell Dec 7, 2024
03ed6ab
dev
davidhassell Dec 7, 2024
8b127c1
dev
davidhassell Dec 8, 2024
d6904b0
dev
davidhassell Dec 8, 2024
4c586e3
dev
davidhassell Dec 9, 2024
24435d9
dev
davidhassell Dec 10, 2024
0975457
dev
davidhassell Jan 10, 2025
c333b62
tidy
davidhassell Jan 29, 2025
242c57c
Merge branch 'main' into cfa-in-cfdm
davidhassell Jan 29, 2025
bd5e508
PP unpack
davidhassell Feb 7, 2025
5d282ba
dev
davidhassell Feb 17, 2025
62c322d
fix up redundant files
davidhassell Feb 18, 2025
38ce6d4
Merge branch 'main' into cfa-in-cfdm
sadielbartholomew Feb 20, 2025
2c4e00d
Fix typos
davidhassell Feb 24, 2025
32a722b
Plurals in message
davidhassell Feb 24, 2025
09cf4c7
Remove dead code
davidhassell Feb 24, 2025
d800005
h5py>=3.12.0
davidhassell Feb 24, 2025
7ad74d0
Update cf/test/test_docstring.py
davidhassell Feb 24, 2025
5da6db9
dev
davidhassell Feb 24, 2025
55be346
dev
davidhassell Feb 24, 2025
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
8 changes: 7 additions & 1 deletion Changelog.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
version 3.17.0
--------------

**2025-02-??**
**2025-??-??**

* Replace dataset aggregation functionality (CFA) with that imported
from `cfdm` (https://github.com/NCAS-CMS/cf-python/issues/841)
* New keyword parameter to `cf.Field.compute_vertical_coordinates`:
``key`` (https://github.com/NCAS-CMS/cf-python/issues/802)
* Changed dependency: ``1.12.0.0<=cfdm<1.12.1.0``
* Changed dependency: ``h5py>=3.12.0``

----


version 3.16.3
Expand Down
21 changes: 5 additions & 16 deletions cf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@
raise ImportError(_error0 + str(error1))

__cf_version__ = cfdm.core.__cf_version__
__cfa_version__ = "0.6.2"

from packaging.version import Version
import importlib.util
Expand Down Expand Up @@ -207,13 +206,10 @@
)

# Check the version of cfdm
_minimum_vn = "1.11.2.0"
_maximum_vn = "1.11.3.0"
if (
not Version(_minimum_vn)
<= Version(cfdm.__version__)
< Version(_maximum_vn)
):
_minimum_vn = "1.12.0.0"
_maximum_vn = "1.12.1.0"
_cfdm_version = Version(cfdm.__version__)
if not Version(_minimum_vn) <= _cfdm_version < Version(_maximum_vn):
raise RuntimeError(
f"Bad cfdm version: cf requires {_minimum_vn}<=cfdm<{_maximum_vn}. "
f"Got {cfdm.__version__} at {cfdm.__file__}"
Expand Down Expand Up @@ -291,10 +287,9 @@
from .field import Field
from .data import Data
from .data.array import (
AggregatedArray,
BoundsFromNodesArray,
CellConnectivityArray,
CFAH5netcdfArray,
CFANetCDF4Array,
FullArray,
GatheredArray,
H5netcdfArray,
Expand All @@ -308,12 +303,6 @@
UMArray,
)

from .data.fragment import (
FullFragmentArray,
NetCDFFragmentArray,
UMFragmentArray,
)

from .aggregate import aggregate, climatology_cells
from .query import (
Query,
Expand Down
98 changes: 81 additions & 17 deletions cf/aggregate.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ def __init__(
# Promote selected properties to field ancillaries that span
# the same domain axes as the field
# ------------------------------------------------------------
self.promoted_field_ancillaries = []
if field_ancillaries:
f = self.promote_to_field_ancillary(field_ancillaries)

Expand Down Expand Up @@ -2088,13 +2089,6 @@ def promote_to_field_ancillary(self, properties):
ancillary construct that spans the entire domain, with the
constant value of the property.

The `Data` of any new field ancillary construct is marked
as a CFA term, meaning that it will only be written to disk if
the parent field construct is written as a CFA aggregation
variable, and in that case the field ancillary is written as a
non-standard CFA aggregation instruction variable, rather than
a CF-netCDF ancillary variable.

If a domain construct is being aggregated then it is always
returned unchanged.

Expand Down Expand Up @@ -2125,7 +2119,6 @@ def promote_to_field_ancillary(self, properties):
data = Data(
FullArray(value, shape=f.shape, dtype=np.array(value).dtype)
)
data._cfa_set_term(True)

field_anc = FieldAncillary(
data=data, properties={"long_name": prop}, copy=False
Expand All @@ -2137,9 +2130,15 @@ def promote_to_field_ancillary(self, properties):
f = f.copy()
copy = False

f.set_construct(field_anc, axes=f.get_data_axes(), copy=False)
key = f.set_construct(
field_anc, axes=f.get_data_axes(), copy=False
)
f.del_property(prop)

# Record that this field ancillary is derived from a
# promotion
self.promoted_field_ancillaries.append(key)

self.field = f
return f

Expand Down Expand Up @@ -2434,9 +2433,9 @@ def aggregate(
Create new field ancillary constructs for each input field
which has one or more of the given properties. For each
input field, each property is converted to a field
ancillary construct that spans the entire domain, with the
constant value of the property, and the property itself is
deleted.
ancillary construct that spans the aggregation axes with
the constant value of the property, and the property
itself is deleted.

.. versionadded:: 3.15.0

Expand Down Expand Up @@ -3039,6 +3038,9 @@ def aggregate(

unaggregatable = False

# Record the names of the axes that are actually aggregated
axes_aggregated = []

for axis in aggregating_axes:
number_of_fields = len(meta)
if number_of_fields == 1:
Expand Down Expand Up @@ -3251,6 +3253,7 @@ def aggregate(
# the aggregated fields as a single list ready for
# aggregation along the next axis.
# --------------------------------------------------------
axes_aggregated.append(axis)
meta = [m for gm in grouped_meta for m in gm]

# Add fields to the output list
Expand All @@ -3267,6 +3270,10 @@ def aggregate(
if cells:
_set_cell_conditions(output_meta)

# Remove non-aggregated axes from promoted field ancillaries
if field_ancillaries:
_fix_promoted_field_ancillaries(output_meta, axes_aggregated)

output_constructs = [m.field for m in output_meta]

aggregate.status = status
Expand Down Expand Up @@ -4724,6 +4731,14 @@ def _aggregate_2_fields(
hash_value1 = anc1["hash_value"]
anc0["hash_value"] = hash_value0 + hash_value1

# The result of aggregating a promoted amd non-promoted
# field ancillary is a non-promoted field ancillary
if (
key0 in m0.promoted_field_ancillaries
and key1 not in m1.promoted_field_ancillaries
):
m0.promoted_field_ancillaries.remove(key0)

# Domain ancillaries
for identity in m0.domain_anc:
anc0 = m0.domain_anc[identity]
Expand All @@ -4745,9 +4760,9 @@ def _aggregate_2_fields(
anc0["hash_value"] = hash_value0 + hash_value1

# ----------------------------------------------------------------
# For each matching pair of coordinates, cell measures, field and
# domain ancillaries which span the aggregating axis, insert the
# one from parent1 into the one from parent0
# For each matching pair of coordinates, cell measures, and field
# and domain ancillaries which span the aggregating axis, insert
# the one from parent1 into the one from parent0
# ----------------------------------------------------------------
for key0, key1, construct0, construct1 in spanning_variables:
construct_axes0 = parent0.get_data_axes(key0)
Expand Down Expand Up @@ -4909,7 +4924,7 @@ def _aggregate_2_fields(
actual_range = parent0.del_property("actual_range", None)
if actual_range is not None and is_log_level_info(logger):
logger.info(
"Deleted 'actual_range' attribute due to being "
"Deleted 'actual_range' attribute due to it being "
"outside of 'valid_range' attribute limits."
)

Expand All @@ -4919,7 +4934,6 @@ def _aggregate_2_fields(

# Make a note that the parent construct in this _Meta object has
# already been aggregated

m0.aggregated_field = True

# ----------------------------------------------------------------
Expand Down Expand Up @@ -4986,3 +5000,53 @@ def dsg_feature_type_axis(meta, axis):
# cf_role property
cf_role = coords["cf_role"]
return cf_role.count(None) != len(cf_role)


def _fix_promoted_field_ancillaries(output_meta, axes_aggregated):
"""Remove non-aggregated axes from promoted field ancillaries.

.. versionadded:: NEXTVERSION

:Parameters:

output_meta: `list`
The list of `_Meta` objects. If any include promoted field
ancillaries then these will be updated in-place.

:Returns:

`None`

"""
for m in output_meta:
for value in m.field_anc.values():
index = []
squeeze = []

key = value["key"]
if key not in m.promoted_field_ancillaries:
continue

# Remove the non-aggregated axes from the promoted field
# ancillary
for i, axis in enumerate(value["axes"]):
if axis in axes_aggregated:
index.append(slice(None))
else:
index.append(0)
squeeze.append(i)

if not squeeze:
continue

fa_axes = m.field.get_data_axes(key)
fa = m.field.del_construct(key)
fa = fa[tuple(index)]
fa.squeeze(squeeze, inplace=True)
fa_axes = [a for i, a in enumerate(fa_axes) if i not in squeeze]

# Record the field ancillary as being able to be written
# as a CF-netCDF aggregation 'value' variable
fa.data._nc_set_aggregation_fragment_type("value")

m.field.set_construct(fa, axes=fa_axes, copy=False)
42 changes: 2 additions & 40 deletions cf/cfimplementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@
)
from .data import Data
from .data.array import (
AggregatedArray,
BoundsFromNodesArray,
CellConnectivityArray,
CFAH5netcdfArray,
CFANetCDF4Array,
GatheredArray,
H5netcdfArray,
NetCDF4Array,
Expand Down Expand Up @@ -114,49 +113,14 @@ def set_construct(self, parent, construct, axes=None, copy=True, **kwargs):
parent, construct, axes=axes, copy=copy, **kwargs
)

def initialise_CFANetCDF4Array(self, **kwargs):
"""Return a `CFANetCDF4Array` instance.

:Parameters:

kwargs: optional
Initialisation parameters to pass to the new instance.

:Returns:

`CFANetCDF4Array`

"""
cls = self.get_class("CFANetCDF4Array")
return cls(**kwargs)

def initialise_CFAH5netcdfArray(self, **kwargs):
"""Return a `CFAH5netcdfArray` instance.

.. versionadded:: 1.11.2.0

:Parameters:

kwargs: optional
Initialisation parameters to pass to the new instance.

:Returns:

`CFAH5netcdfArray`

"""
cls = self.get_class("CFAH5netcdfArray")
return cls(**kwargs)


_implementation = CFImplementation(
cf_version=CF(),
AggregatedArray=AggregatedArray,
AuxiliaryCoordinate=AuxiliaryCoordinate,
CellConnectivity=CellConnectivity,
CellMeasure=CellMeasure,
CellMethod=CellMethod,
CFAH5netcdfArray=CFAH5netcdfArray,
CFANetCDF4Array=CFANetCDF4Array,
CoordinateReference=CoordinateReference,
DimensionCoordinate=DimensionCoordinate,
Domain=Domain,
Expand Down Expand Up @@ -214,8 +178,6 @@ def implementation():
'CellConnectivityArray': cf.data.array.cellconnectivityarray.CellConnectivityArray,
'CellMeasure': cf.cellmeasure.CellMeasure,
'CellMethod': cf.cellmethod.CellMethod,
'CFAH5netcdfArray': cf.data.array.cfah5netcdfarray.CFAH5netcdfArray,
'CFANetCDF4Array': cf.data.array.cfanetcdf4array.CFANetCDF4Array,
'CoordinateReference': cf.coordinatereference.CoordinateReference,
'DimensionCoordinate': cf.dimensioncoordinate.DimensionCoordinate,
'Domain': cf.domain.Domain,
Expand Down
3 changes: 1 addition & 2 deletions cf/data/array/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from .aggregatedarray import AggregatedArray
from .boundsfromnodesarray import BoundsFromNodesArray
from .cellconnectivityarray import CellConnectivityArray
from .cfah5netcdfarray import CFAH5netcdfArray
from .cfanetcdf4array import CFANetCDF4Array
from .fullarray import FullArray
from .gatheredarray import GatheredArray
from .h5netcdfarray import H5netcdfArray
Expand Down
1 change: 0 additions & 1 deletion cf/data/array/abstract/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from .array import Array
from .filearray import FileArray
3 changes: 1 addition & 2 deletions cf/data/array/abstract/array.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import cfdm

from ....mixin_container import Container
from ..mixin import ArrayMixin


class Array(ArrayMixin, Container, cfdm.Array):
class Array(Container, cfdm.Array):
"""Abstract base class for a container of an underlying array.

The form of the array is defined by the initialisation parameters
Expand Down
Loading