Skip to content

Commit 549476d

Browse files
Merge pull request #844 from sadielbartholomew/compute-vert-coor-new-outputs
Add new `key` parameter to `compute_vertical_coordinates`
2 parents 2cac6e9 + 3b69d09 commit 549476d

File tree

3 files changed

+82
-9
lines changed

3 files changed

+82
-9
lines changed

Changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
version 3.17.0
2+
--------------
3+
4+
**2025-02-??**
5+
6+
* New keyword parameter to `cf.Field.compute_vertical_coordinates`:
7+
``key`` (https://github.com/NCAS-CMS/cf-python/issues/802)
8+
9+
110
version 3.16.3
211
--------------
312

cf/field.py

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9514,7 +9514,12 @@ def domain_mask(self, **kwargs):
95149514
@_inplace_enabled(default=False)
95159515
@_manage_log_level_via_verbosity
95169516
def compute_vertical_coordinates(
9517-
self, default_to_zero=True, strict=True, inplace=False, verbose=None
9517+
self,
9518+
default_to_zero=True,
9519+
strict=True,
9520+
key=False,
9521+
inplace=False,
9522+
verbose=None,
95189523
):
95199524
"""Compute non-parametric vertical coordinates.
95209525

@@ -9549,7 +9554,7 @@ def compute_vertical_coordinates(
95499554
{{default_to_zero: `bool`, optional}}
95509555

95519556
strict: `bool`
9552-
If False then allow the computation to occur when
9557+
If False then allow the computation to occur when:
95539558

95549559
* A domain ancillary construct has no standard name, but
95559560
the corresponding term has a standard name that is
@@ -9568,15 +9573,30 @@ def compute_vertical_coordinates(
95689573
names, then an exception is raised regardless of the value
95699574
of *strict*.
95709575

9576+
key: `bool`
9577+
If True, return alongside the field construct the key
9578+
identifying the auxiliary coordinate of the field with
9579+
the newly-computed vertical coordinates, as a 2-tuple
9580+
of field and then key. If False, the default, then only
9581+
return the field construct.
9582+
9583+
If no coordinates were computed, `None` will be
9584+
returned in the key (second) position of the 2-tuple.
9585+
9586+
.. versionadded:: 3.17.0
9587+
95719588
{{inplace: `bool`, optional}}
95729589

95739590
{{verbose: `int` or `str` or `None`, optional}}
95749591

95759592
:Returns:
95769593

9577-
`Field` or `None`
9594+
`Field`, 2-tuple, or `None`
95789595
The field construct with the new non-parametric vertical
9579-
coordinates, or `None` if the operation was in-place.
9596+
coordinates, or a 2-tuple of this field construct along
9597+
with the key of the new auxiliary coordinate with the
9598+
computed vertical coordinates, or `None` if the operation
9599+
was in-place.
95809600

95819601
**Examples**
95829602

@@ -9603,7 +9623,7 @@ def compute_vertical_coordinates(
96039623
>>> print(f.auxiliary_coordinate('altitude', default=None))
96049624
None
96059625
>>> g = f.compute_vertical_coordinates()
9606-
>>> print(g.auxiliary_coordinates)
9626+
>>> print(g.auxiliary_coordinates())
96079627
Constructs:
96089628
{'auxiliarycoordinate0': <CF AuxiliaryCoordinate: latitude(10, 9) degrees_N>,
96099629
'auxiliarycoordinate1': <CF AuxiliaryCoordinate: longitude(9, 10) degrees_E>,
@@ -9619,12 +9639,35 @@ def compute_vertical_coordinates(
96199639
Bounds:units = 'm'
96209640
Bounds:Data(1, 10, 9, 2) = [[[[5.0, ..., 5415.0]]]] m
96219641

9642+
>>> g, key = f.compute_vertical_coordinates(key=True)
9643+
>>> g
9644+
<CF Field: air_temperature(atmosphere_hybrid_height_coordinate(1), grid_latitude(10), grid_longitude(9)) K>
9645+
>>> key
9646+
'auxiliarycoordinate3'
9647+
9648+
>>> i = f.compute_vertical_coordinates(inplace=True)
9649+
>>> print(i)
9650+
None
9651+
>>> print(f.auxiliary_coordinates())
9652+
Constructs:
9653+
{'auxiliarycoordinate0': <CF AuxiliaryCoordinate: latitude(10, 9) degrees_N>,
9654+
'auxiliarycoordinate1': <CF AuxiliaryCoordinate: longitude(9, 10) degrees_E>,
9655+
'auxiliarycoordinate2': <CF AuxiliaryCoordinate: long_name=Grid latitude name(10) >,
9656+
'auxiliarycoordinate3': <CF AuxiliaryCoordinate: altitude(1, 10, 9) m>}
9657+
96229658
"""
96239659
f = _inplace_enabled_define_and_cleanup(self)
96249660

9661+
if inplace and key:
9662+
raise ValueError(
9663+
"Can't set both key=True and inplace=True, since inplace "
9664+
"will always do the operation in-place and return None."
9665+
)
9666+
96259667
detail = is_log_level_detail(logger)
96269668
debug = is_log_level_debug(logger)
96279669

9670+
return_key = None # in case there are no vertical coords to compute
96289671
for cr in f.coordinate_references(todict=True).values():
96299672
# --------------------------------------------------------
96309673
# Compute the non-parametric vertical coordinates, if
@@ -9666,20 +9709,25 @@ def compute_vertical_coordinates(
96669709
f"{c.dump(display=False, _level=1)}"
96679710
) # pragma: no cover
96689711

9669-
key = f.set_construct(c, axes=computed_axes, copy=False)
9712+
return_key = f.set_construct(c, axes=computed_axes, copy=False)
96709713

96719714
# Reference the new coordinates from the coordinate
96729715
# reference construct
9673-
cr.set_coordinate(key)
9716+
cr.set_coordinate(return_key)
96749717

96759718
if debug:
96769719
logger.debug(
9677-
f"Non-parametric coordinates construct key: {key!r}\n"
9720+
"Non-parametric coordinates construct key: "
9721+
f"{return_key!r}\n"
96789722
"Updated coordinate reference construct:\n"
96799723
f"{cr.dump(display=False, _level=1)}"
96809724
) # pragma: no cover
96819725

9682-
return f
9726+
if key:
9727+
# 2-tuple, where return_key will be None if nothing was computed
9728+
return f, return_key
9729+
else:
9730+
return f
96839731

96849732
def match_by_construct(self, *identities, OR=False, **conditions):
96859733
"""Whether or not there are particular metadata constructs.

cf/test/test_formula_terms.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,17 @@ def test_compute_vertical_coordinates(self):
757757
g = f.compute_vertical_coordinates(verbose=None)
758758
altitude = g.auxiliary_coordinate("altitude")
759759

760+
# Test the 'key' parameter
761+
k = f.compute_vertical_coordinates(key=True, verbose=None)
762+
self.assertEqual(len(k), 2) # expect a 2-tuple of field then key
763+
self.assertTrue(k[0].equals(g)) # field result, same as above
764+
self.assertEqual(k[1], "auxiliarycoordinate3") # i.e. key for altitude
765+
# key=True and inplace=True are incompatible inputs
766+
with self.assertRaises(ValueError):
767+
k = f.compute_vertical_coordinates(
768+
key=True, inplace=True, verbose=None
769+
)
770+
760771
self.assertTrue(altitude)
761772
self.assertTrue(altitude.has_bounds())
762773
self.assertEqual(altitude.shape, (1,) + orog.shape)
@@ -881,6 +892,11 @@ def test_compute_vertical_coordinates(self):
881892
f = cf.example_field(0)
882893
g = f.compute_vertical_coordinates()
883894
self.assertTrue(g.equals(f))
895+
# With key=True, expect the key (second in return 2-tuple) to be None
896+
k = f.compute_vertical_coordinates(key=True)
897+
self.assertEqual(len(k), 2)
898+
self.assertTrue(k[0].equals(f))
899+
self.assertEqual(k[1], None)
884900

885901
# ------------------------------------------------------------
886902
# Check other types

0 commit comments

Comments
 (0)