Skip to content

Commit 2cfc8e6

Browse files
authored
Merge pull request NCAS-CMS#693 from davidhassell/aggregation-cell
Record dimension coordinate cell characteristics
2 parents 88febb7 + 929e650 commit 2cfc8e6

File tree

6 files changed

+471
-95
lines changed

6 files changed

+471
-95
lines changed

Changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ version 3.15.4
33

44
**2023-??-??**
55

6+
* Record dimension coordinate cell characteristics
7+
(https://github.com/NCAS-CMS/cf-python/issues/692)
8+
* New set of methods to query, set, del, and `get_cell_characterstics`
69
* Fix bug in `cf.Field.match_by_construct` that always returned True for
710
1-d constructs whose axis is not in the data, even when the
811
criterion was not matched

cf/aggregate.py

Lines changed: 87 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,7 +2311,7 @@ def aggregate(
23112311
**Units**
23122312
23132313
Units must be provided on the conditions where applicable,
2314-
since conditions without defined units do not match
2314+
since conditions without defined units will not match
23152315
dimension coordinate constructs with defined units.
23162316
23172317
**Multiple conditions**
@@ -2358,18 +2358,26 @@ def aggregate(
23582358
23592359
>>> x = cf.aggregate(fl, cells=cf.climatology_cells())
23602360
2361+
**Storage of conditions**
2362+
2363+
All returned field or domain constructs that have passed
2364+
dimension coordinate cell conditions will have those
2365+
conditions stored on the appropriate dimension coordinate
2366+
constructs, retrievable via their
2367+
`DimensionCoordinate.get_cell_characteristics` methods.
2368+
23612369
**Performance**
23622370
23632371
The testing of the conditions has a computational
23642372
overhead, as well as an I/O overhead if the dimension
2365-
coordinate data are on disk. Try to avoid setting redundant
2366-
conditions. For instance, if the inputs comprise monthly mean air
2367-
temperature and daily mean precipitation fields, then the
2368-
different field identities alone will ensure a correct
2369-
aggregation. In this case, adding cell conditions of
2370-
``{'T': [{'cellsize': cf.D()}, {'cellsize': cf.M()}]}``
2371-
will not change the result, but tests will still be
2372-
carried out.
2373+
coordinate data are on disk. Try to avoid setting
2374+
redundant conditions. For instance, if the inputs comprise
2375+
monthly mean air temperature and daily mean precipitation
2376+
fields, then the different field identities alone will
2377+
ensure a correct aggregation. In this case, adding cell
2378+
conditions of ``{'T': [{'cellsize': cf.D()}, {'cellsize':
2379+
cf.M()}]}`` will not change the result, but tests will
2380+
still be carried out.
23732381
23742382
When setting a sequence of conditions, performance will be
23752383
improved if the conditions towards the beginning of the
@@ -2489,9 +2497,9 @@ def aggregate(
24892497
# Initialise the cache of canonical metadata attributes
24902498
canonical = _Canonical()
24912499

2492-
output_constructs = []
2493-
2494-
output_constructs_append = output_constructs.append
2500+
output_meta = []
2501+
output_meta_append = output_meta.append
2502+
output_meta_extend = output_meta.extend
24952503

24962504
if exclude:
24972505
exclude = " NOT"
@@ -2655,10 +2663,10 @@ def aggregate(
26552663
# This field does not have a structural signature, so
26562664
# it can't be aggregated. Put it straight into the
26572665
# output list and move on to the next input construct.
2658-
if not copy:
2659-
output_constructs_append(f)
2660-
else:
2661-
output_constructs_append(f.copy())
2666+
if copy:
2667+
meta = meta.copy()
2668+
2669+
output_meta_append(meta)
26622670

26632671
continue
26642672

@@ -2724,11 +2732,10 @@ def aggregate(
27242732
# add it straight to the output list and move on to the
27252733
# next signature.
27262734
# --------------------------------------------------------
2727-
if not copy:
2728-
output_constructs_append(meta[0].field)
2729-
else:
2730-
output_constructs_append(meta[0].field.copy())
2735+
if copy:
2736+
meta[0] = meta[0].copy()
27312737

2738+
output_meta_append(meta[0])
27322739
continue
27332740

27342741
if not relaxed_units and not meta[0].units.isvalid:
@@ -2741,9 +2748,9 @@ def aggregate(
27412748

27422749
if not exclude:
27432750
if copy:
2744-
output_constructs.extend(m.field.copy() for m in meta)
2751+
output_meta_extend(m.copy() for m in meta)
27452752
else:
2746-
output_constructs.extend(m.field for m in meta)
2753+
output_meta_extend(meta)
27472754

27482755
continue
27492756

@@ -3035,11 +3042,16 @@ def aggregate(
30353042
status = 1
30363043
if not exclude:
30373044
if copy:
3038-
output_constructs.extend((m.field.copy() for m in meta0))
3045+
output_meta_extend(m.copy() for m in meta0)
30393046
else:
3040-
output_constructs.extend((m.field for m in meta0))
3047+
output_meta_extend(meta0)
30413048
else:
3042-
output_constructs.extend((m.field for m in meta))
3049+
output_meta_extend(meta)
3050+
3051+
if cells:
3052+
_set_cell_conditions(output_meta)
3053+
3054+
output_constructs = [m.field for m in output_meta]
30433055

30443056
aggregate.status = status
30453057

@@ -3058,6 +3070,52 @@ def aggregate(
30583070
return output_constructs
30593071

30603072

3073+
def _set_cell_conditions(output_meta):
3074+
"""Store the cell characteristics from any cell conditions.
3075+
3076+
The cell size and cell spacing characteristics are stored on the
3077+
appropriate dimension coordinate constructs.
3078+
3079+
.. versionadded:: 3.15.4
3080+
3081+
:Parameters:
3082+
3083+
output_meta: `list`
3084+
The list of `_Meta` objects, each of which contains an
3085+
output field or domain construct. The field or constructs
3086+
are updated in-place.
3087+
3088+
:Returns:
3089+
3090+
`None`
3091+
3092+
"""
3093+
for m in output_meta:
3094+
for value in m.axis.values():
3095+
dim_index = value["dim_coord_index"]
3096+
if dim_index is None:
3097+
# There is no dimension coordinate construct for this
3098+
# axis
3099+
continue
3100+
3101+
cellsize = value["cellsize"][dim_index]
3102+
if cellsize is None:
3103+
# There is no cell size condition
3104+
continue
3105+
3106+
spacing = value["spacing"][dim_index]
3107+
if spacing is None:
3108+
# There is no cell spacing condition
3109+
continue
3110+
3111+
# Set the cell conditions on the dimension coordinate
3112+
# construct
3113+
dim_coord = m.field.dimension_coordinate(value["keys"][dim_index])
3114+
dim_coord.set_cell_characteristics(
3115+
cellsize=cellsize, spacing=spacing
3116+
)
3117+
3118+
30613119
# --------------------------------------------------------------------
30623120
# Initialise the status
30633121
# --------------------------------------------------------------------
@@ -3179,7 +3237,7 @@ def climatology_cells(
31793237
{'cellsize': <CF Query: (isclose 12 hour)>},
31803238
{'cellsize': <CF TimeDuration: P1M (Y-M-01 00:00:00)>}]}
31813239
3182-
Add a condition that separately aggregates decadal data:
3240+
Add a condition for decadal data:
31833241
31843242
>>> cells['T'].append({'cellsize': cf.wi(3600, 3660, 'day')})
31853243
>>> cells
@@ -4169,6 +4227,7 @@ def _aggregate_2_fields(
41694227
verbose=None,
41704228
concatenate=True,
41714229
data_concatenation=None,
4230+
cell_conditions=None,
41724231
relaxed_units=False,
41734232
copy=True,
41744233
):
@@ -4192,7 +4251,8 @@ def _aggregate_2_fields(
41924251
41934252
data_concatenation: `dict`
41944253
The dictionary that contains the data arrays for each
4195-
construct type that will need concatenating.
4254+
construct type that will need concatenating. Will be
4255+
updated in-place.
41964256
41974257
.. versionadded:: 3.15.1
41984258
@@ -4248,10 +4308,6 @@ def _aggregate_2_fields(
42484308
hash_values1 = m1.hash_values[a_identity]
42494309

42504310
for i, (hash0, hash1) in enumerate(zip(hash_values0, hash_values1)):
4251-
# try:
4252-
# hash_values0[i].append(hash_values1[i])
4253-
# except AttributeError:
4254-
# hash_values0[i] = [hash_values0[i], hash_values1[i]]
42554311
hash_values0[i] = hash_values0[i] + hash_values1[i]
42564312

42574313
# N-d auxiliary coordinates

0 commit comments

Comments
 (0)