Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 0 additions & 42 deletions cf/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -3006,48 +3006,6 @@ def close(self):
removed_at="5.0.0",
) # pragma: no cover

def iscyclic(self, *identity, **filter_kwargs):
"""Returns True if the specified axis is cyclic.

.. versionadded:: 1.0

.. seealso:: `axis`, `cyclic`, `period`, `domain_axis`

:Parameters:

identity, filter_kwargs: optional
Select the unique domain axis construct returned by
``f.domain_axis(*identity, **filter_kwargs)``. See
`domain_axis` for details.

:Returns:

`bool`
True if the selected axis is cyclic, otherwise False.

**Examples**

>>> f.iscyclic('X')
True
>>> f.iscyclic('latitude')
False

>>> x = f.iscyclic('long_name=Latitude')
>>> x = f.iscyclic('dimensioncoordinate1')
>>> x = f.iscyclic('domainaxis2')
>>> x = f.iscyclic('key%domainaxis2')
>>> x = f.iscyclic('ncdim%y')
>>> x = f.iscyclic(2)

"""
axis = self.domain_axis(
*identity, key=True, default=None, **filter_kwargs
)
if axis is None:
raise ValueError("Can't identify unique domain axis")

return axis in self.cyclic()

def weights(
self,
weights=True,
Expand Down
49 changes: 39 additions & 10 deletions cf/mixin/fielddomain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1345,10 +1345,14 @@ def autocyclic(self, key=None, coord=None, verbose=None, config={}):
# Don't do anything
return

# On a dry run, return as usual, but don't update _cyclic.
dry_run = config.get("dry_run")

if "cyclic" in config:
if not config["cyclic"]:
if not noop:
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False
else:
period = coord.period()
Expand All @@ -1357,7 +1361,11 @@ def autocyclic(self, key=None, coord=None, verbose=None, config={}):
else:
period = config.get("period")

self.cyclic(key, iscyclic=True, period=period, config=config)
if not dry_run:
self.cyclic(
key, iscyclic=True, period=period, config=config
)

return True

if coord is None:
Expand All @@ -1366,14 +1374,17 @@ def autocyclic(self, key=None, coord=None, verbose=None, config={}):
)
if coord is None:
return False

elif "X" in config:
if not config["X"]:
if not noop:
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False
elif not coord.X:
if not noop:
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False

bounds_range = config.get("bounds_range")
Expand All @@ -1382,14 +1393,16 @@ def autocyclic(self, key=None, coord=None, verbose=None, config={}):
else:
bounds = coord.get_bounds(None)
if bounds is None:
if not noop:
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False

data = bounds.get_data(None, _fill_value=False)
if data is None:
if not noop:
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False

bounds_units = bounds.Units
Expand All @@ -1411,7 +1424,9 @@ def autocyclic(self, key=None, coord=None, verbose=None, config={}):
elif bounds_units.equivalent(_units_degrees):
period = Data(360.0, units="degrees")
else:
self.cyclic(key, iscyclic=False, config=config)
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False

period.Units = bounds_units
Expand All @@ -1422,14 +1437,16 @@ def autocyclic(self, key=None, coord=None, verbose=None, config={}):
bounds_range = None

if bounds_range is None or bounds_range != period:
if not noop:
if not dry_run:
self.cyclic(key, iscyclic=False, config=config)

return False

config = config.copy()
config["axis"] = self.get_data_axes(key, default=(None,))[0]

self.cyclic(key, iscyclic=True, period=period, config=config)
if not dry_run:
self.cyclic(key, iscyclic=True, period=period, config=config)

return True

Expand Down Expand Up @@ -1885,6 +1902,7 @@ def cyclic(
coordinates, otherwise it is assumed to have the same
units as the dimension coordinates.


config: `dict`, optional
Additional parameters for optimising the
operation. See the code for details.
Expand Down Expand Up @@ -1923,7 +1941,18 @@ def cyclic(
cyclic = self._cyclic

if not identity and not filter_kwargs:
return cyclic.copy()
cyclic = cyclic.copy()

# Check for axes that are currently marked as non-cyclic,
# but are in fact cyclic.
if (
len(cyclic) < len(self.domain_axes(todict=True))
and self.autocyclic()
):
cyclic.update(self._cyclic)
self._cyclic = cyclic

return cyclic

axis = config.get("axis")
if axis is None:
Expand Down
37 changes: 33 additions & 4 deletions cf/test/test_Domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,24 +437,53 @@ def test_Domain_cyclic_iscyclic(self):
d2 = f2.domain

# Getting
self.assertEqual(d1.cyclic(), f1.cyclic())
self.assertEqual(d1.cyclic(), set())
self.assertEqual(d1.cyclic(), f1.cyclic())
self.assertFalse(d1.iscyclic("X"))
self.assertFalse(d1.iscyclic("Y"))
self.assertFalse(d1.iscyclic("Z"))
self.assertFalse(d1.iscyclic("T"))
self.assertEqual(d2.cyclic(), f2.cyclic())

self.assertEqual(d2.cyclic(), set(("domainaxis2",)))
self.assertEqual(d2.cyclic(), f2.cyclic())
self.assertTrue(d2.iscyclic("X"))
self.assertFalse(d2.iscyclic("Y"))
self.assertFalse(d2.iscyclic("Z"))
self.assertFalse(d2.iscyclic("T"))

# Setting
self.assertEqual(d2.cyclic("X", iscyclic=False), set(("domainaxis2",)))
self.assertEqual(d2.cyclic(), set())
self.assertEqual(d2.cyclic("X", period=360), set())
self.assertEqual(d2.cyclic(), set(("domainaxis2",)))

d2.cyclic("Y", period=360), set()
self.assertEqual(
d2.cyclic(),
set(
(
"domainaxis1",
"domainaxis2",
)
),
)
self.assertTrue(d2.iscyclic("Y"))
self.assertEqual(
d2.cyclic("Y", iscyclic=False),
set(
(
"domainaxis1",
"domainaxis2",
)
),
)
self.assertEqual(d2.cyclic(), set(("domainaxis2",)))

# Auto setting of cyclicity
self.assertTrue(d2.iscyclic("X"))
d2.cyclic("X", iscyclic=False)
self.assertFalse(d2._cyclic)
self.assertEqual(d2.cyclic(), set(("domainaxis2",)))

d2.cyclic("X", iscyclic=False)
self.assertTrue(d2.iscyclic("X"))


Expand Down
32 changes: 30 additions & 2 deletions cf/test/test_Field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2970,9 +2970,37 @@ def test_Field_cyclic_iscyclic(self):

# Setting
self.assertEqual(f2.cyclic("X", iscyclic=False), set(("domainaxis2",)))
self.assertEqual(f2.cyclic(), set())
self.assertEqual(f2.cyclic("X", period=360), set())
self.assertEqual(f2.cyclic(), set(("domainaxis2",)))

f2.cyclic("Y", period=360), set()
self.assertEqual(
f2.cyclic(),
set(
(
"domainaxis1",
"domainaxis2",
)
),
)
self.assertTrue(f2.iscyclic("Y"))
self.assertEqual(
f2.cyclic("Y", iscyclic=False),
set(
(
"domainaxis1",
"domainaxis2",
)
),
)
self.assertEqual(f2.cyclic(), set(("domainaxis2",)))

# Auto setting of cyclicity
self.assertTrue(f2.iscyclic("X"))
f2.cyclic("X", iscyclic=False)
self.assertFalse(f2._cyclic)
self.assertEqual(f2.cyclic(), set(("domainaxis2",)))

f2.cyclic("X", iscyclic=False)
self.assertTrue(f2.iscyclic("X"))

def test_Field_is_discrete_axis(self):
Expand Down
Loading