Skip to content

Commit 6ac5ae0

Browse files
authored
Merge pull request #886 from davidhassell/collapse-cell-measures
`cf.Field.collapse` fails when cell measure has external data
2 parents 9d022b2 + 96c0f17 commit 6ac5ae0

File tree

3 files changed

+66
-46
lines changed

3 files changed

+66
-46
lines changed

Changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Version NEXTVERSION
99
* Allow multiple conditions for the same axis in `cf.Field.subspace`
1010
and `cf.Field.indices`
1111
(https://github.com/NCAS-CMS/cf-python/issues/881)
12+
* Fix bug in `cf.Field.collapse` that causes a ``ValueError`` to be raised
13+
for missing external cell measures data
14+
(https://github.com/NCAS-CMS/cf-python/issues/885)
1215
* New dependency: ``distributed>=2025.5.1``
1316

1417
----

cf/field.py

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3708,7 +3708,12 @@ def weights(
37083708
weights_axes.discard(xaxis)
37093709
weights_axes.discard(yaxis)
37103710
if not Weights.cell_measure(
3711-
self, "area", comp, weights_axes, methods=methods
3711+
self,
3712+
"area",
3713+
comp,
3714+
weights_axes,
3715+
methods=methods,
3716+
auto=True,
37123717
):
37133718
Weights.area_XY(
37143719
self,
@@ -5472,52 +5477,60 @@ def collapse(
54725477

54735478
weights: optional
54745479
Specify the weights for the collapse axes. The weights
5475-
are, in general, those that would be returned by this
5476-
call of the field construct's `weights` method:
5477-
``f.weights(weights, axes=axes, measure=measure,
5478-
scale=scale, radius=radius, great_circle=great_circle,
5479-
components=True)``. See the *axes*, *measure*,
5480-
*scale*, *radius* and *great_circle* parameters and
5481-
`cf.Field.weights` for details, and note that the
5482-
value of *scale* may be modified depending on the
5483-
value of *measure*.
5480+
are created internally as the output of this call of
5481+
the field construct's `weights` method:
5482+
``f.weights(weights, components=True, axes=axes,
5483+
measure=measure, scale=scale, radius=radius,
5484+
great_circle=great_circle)``.
54845485

5485-
.. note:: By default *weights* is `None`, resulting in
5486-
**unweighted calculations**.
5486+
See the `cf.Field.weights` and the *axes*, *measure*,
5487+
*scale*, *radius*, and *great_circle* parameters for
5488+
details; and note that the value of *scale* may be
5489+
modified depending on the value of *measure*.
5490+
5491+
.. warning:: By default *weights* is `None`, resulting
5492+
in **unweighted calculations**.
5493+
5494+
.. note:: Setting *weights* to `True` is generally a
5495+
good way to ensure that all collapses are
5496+
appropriately weighted according to the
5497+
field construct's metadata. In this case, if
5498+
it is not possible to create weights for any
5499+
axis then an exception will be raised.
54875500

54885501
.. note:: Unless the *method* is ``'integral'``, the
54895502
units of the weights are not combined with
54905503
the field's units in the collapsed field.
54915504

5492-
If the alternative form of providing the collapse method
5493-
and axes combined as a CF cell methods-like string via the
5494-
*method* parameter has been used, then the *axes*
5495-
parameter is ignored and the axes are derived from the
5496-
*method* parameter. For example, if *method* is ``'T:
5497-
area: minimum'`` then this defines axes of ``['T',
5505+
.. note:: A pre-calculated weights array or dictionary
5506+
may also be provided as the *weights*
5507+
parameter. See `cf.Field.weights` for
5508+
details
5509+
5510+
If the collapse method and axes have been provided as
5511+
a CF cell methods-like string via the *method*
5512+
parameter, then the *axes* parameter is ignored and
5513+
the axes for weights instead inferred from that
5514+
string. For instance, if *method* is ``'T: area:
5515+
minimum'`` then this defines axes of ``['T',
54985516
'area']``. If *method* specifies multiple collapses,
5499-
e.g. ``'T: minimum area: mean'`` then this implies axes of
5500-
``'T'`` for the first collapse, and axes of ``'area'`` for
5501-
the second collapse.
5502-
5503-
.. note:: Setting *weights* to `True` is generally a good
5504-
way to ensure that all collapses are
5505-
appropriately weighted according to the field
5506-
construct's metadata. In this case, if it is not
5507-
possible to create weights for any axis then an
5508-
exception will be raised.
5509-
5510-
However, care needs to be taken if *weights* is
5511-
`True` when cell volume weights are desired. The
5512-
volume weights will be taken from a "volume"
5513-
cell measure construct if one exists, otherwise
5514-
the cell volumes will be calculated as being
5515-
proportional to the sizes of one-dimensional
5516-
vertical coordinate cells. In the latter case
5517-
**if the vertical dimension coordinates do not
5518-
define the actual height or depth thickness of
5519-
every cell in the domain then the weights will
5520-
be incorrect**.
5517+
e.g. ``'T: minimum area: mean'`` then this implies
5518+
axes of ``'T'`` for the first collapse, and axes of
5519+
``'area'`` for the second collapse.
5520+
5521+
.. warning:: Care needs to be taken if *weights* is
5522+
set to `True` when cell volume weights
5523+
are desired. The volume weights will be
5524+
taken from a "volume" cell measure
5525+
construct if one exists, otherwise the
5526+
cell volumes will be calculated as being
5527+
proportional to the sizes of
5528+
one-dimensional vertical coordinate
5529+
cells. In the latter case **if the
5530+
vertical dimension coordinates do not
5531+
define the actual height or depth
5532+
thickness of every cell in the domain
5533+
then the weights will be incorrect**.
55215534

55225535
*Parameter example:*
55235536
To specify weights based on the field construct's

cf/weights.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,15 +1508,16 @@ def cell_measure(
15081508
return False
15091509

15101510
raise ValueError(
1511-
f"Can't find weights: No {measure!r} cell measure"
1511+
f"Can't find weights for {f!r}: No {measure!r} cell measure"
15121512
)
15131513

15141514
elif len_m > 1:
15151515
if auto:
15161516
return False
15171517

15181518
raise ValueError(
1519-
f"Can't find weights: Multiple {measure!r} cell measures"
1519+
f"Can't find weights for {f!r}: Multiple {measure!r} cell "
1520+
"measures"
15201521
)
15211522

15221523
key, clm = m.popitem()
@@ -1526,9 +1527,11 @@ def cell_measure(
15261527
return False
15271528

15281529
raise ValueError(
1529-
f"Can't find weights: Cell measure {m!r} has no data, "
1530-
"possibly because it is external. "
1531-
"Consider setting cell_measures=False"
1530+
f"Can't find weights for {f!r}: Cell measure {clm!r} has no "
1531+
"data, possibly because it is in a missing external file. "
1532+
"Consider setting cell_measures=False or, if applicable, "
1533+
"re-reading the dataset whilst providing the external "
1534+
"file (see cf.read for details)."
15321535
)
15331536

15341537
clm_axes0 = f.get_data_axes(key)
@@ -1543,7 +1546,8 @@ def cell_measure(
15431546
return False
15441547

15451548
raise ValueError(
1546-
"Multiple weights specifications for "
1549+
f"Can't find weights for {f!r}: Multiple weights "
1550+
"specifications for "
15471551
f"{f.constructs.domain_axis_identity(axis)!r} axis"
15481552
)
15491553

0 commit comments

Comments
 (0)