diff --git a/Changelog.rst b/Changelog.rst index 8686b5688a..1f2303de6f 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -44,9 +44,12 @@ version 3.16.2 * Fix bug whereby `Field.cyclic` is not updated after a `Field.del_construct` operation (https://github.com/NCAS-CMS/cf-python/issues/758) +* Fix bug that meant `cyclic()` always returned an empty + set for domains produced by `cf.Field.domain` + (https://github.com/NCAS-CMS/cf-python/issues/762) * Changed dependency: ``cfunits>=3.3.7`` * Changed dependency: ``netCDF4>=1.6.5`` - + ---- version 3.16.1 diff --git a/cf/field.py b/cf/field.py index 7e55e6c979..f0e062b0cb 100644 --- a/cf/field.py +++ b/cf/field.py @@ -2691,6 +2691,30 @@ def cfa_update_file_substitutions( for c in self.constructs.filter_by_data(todict=True).values(): c.cfa_update_file_substitutions(substitutions) + def get_domain(self): + """Return the domain. + + .. versionadded:: NEXTVERSION + + .. seealso:: `domain` + + :Returns: + + `Domain` + The domain. + + **Examples** + + >>> d = f.get_domain() + + """ + domain = super().get_domain() + + # Set axis cyclicity for the domain + domain._cyclic = self._cyclic + + return domain + def radius(self, default=None): """Return the radius of a latitude-longitude plane defined in spherical polar coordinates. @@ -10455,9 +10479,9 @@ def convolution_filter( new_bounds[0 : length - lower_offset, 1:] = old_bounds[ lower_offset:length, 1: ] - new_bounds[ - length - lower_offset : length, 1: - ] = old_bounds[length - 1, 1:] + new_bounds[length - lower_offset : length, 1:] = ( + old_bounds[length - 1, 1:] + ) coord.set_bounds(self._Bounds(data=new_bounds)) diff --git a/cf/mixin/fielddomain.py b/cf/mixin/fielddomain.py index ac57fb6784..9b0e8b7655 100644 --- a/cf/mixin/fielddomain.py +++ b/cf/mixin/fielddomain.py @@ -1909,7 +1909,7 @@ def coordinate_reference_domain_axes(self, identity=None): def cyclic( self, *identity, iscyclic=True, period=None, config={}, **filter_kwargs ): - """Set the cyclicity of an axis. + """Get or set the cyclicity of an axis. .. versionadded:: 1.0 diff --git a/cf/mixin/propertiesdata.py b/cf/mixin/propertiesdata.py index 80269e11e5..a756b4aafe 100644 --- a/cf/mixin/propertiesdata.py +++ b/cf/mixin/propertiesdata.py @@ -2934,7 +2934,7 @@ def count_masked(self): return data.count_masked() def cyclic(self, axes=None, iscyclic=True): - """Set the cyclicity of an axis. + """Get or set the cyclicity of an axis. .. seealso:: `iscyclic` diff --git a/cf/mixin/propertiesdatabounds.py b/cf/mixin/propertiesdatabounds.py index 15434785ce..685f177a94 100644 --- a/cf/mixin/propertiesdatabounds.py +++ b/cf/mixin/propertiesdatabounds.py @@ -1607,7 +1607,7 @@ def cos(self, bounds=True, inplace=False, i=False): ) def cyclic(self, axes=None, iscyclic=True): - """Set the cyclicity of axes of the data array. + """Get or set the cyclicity of axes of the data array. .. seealso:: `iscyclic` diff --git a/cf/test/test_Domain.py b/cf/test/test_Domain.py index 9e5566eab0..63e639df4a 100644 --- a/cf/test/test_Domain.py +++ b/cf/test/test_Domain.py @@ -428,6 +428,35 @@ def test_Domain_del_construct(self): self.assertIsInstance(e.del_construct("domainaxis2"), cf.DomainAxis) self.assertEqual(e.cyclic(), set()) + def test_Domain_cyclic_iscyclic(self): + """Test the `cyclic` and `iscyclic` Domain methods.""" + # A field and its domain should have the same cyclic() output. + f1 = cf.example_field(1) # no cyclic axes + d1 = f1.domain + f2 = cf.example_field(2) # one cyclic axis, 'domainaxis2' ('X') + d2 = f2.domain + + # Getting + self.assertEqual(d1.cyclic(), f1.cyclic()) + self.assertEqual(d1.cyclic(), set()) + 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.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",))) + self.assertTrue(d2.iscyclic("X")) + if __name__ == "__main__": print("Run date:", datetime.datetime.now()) diff --git a/cf/test/test_Field.py b/cf/test/test_Field.py index f3517fbf84..62048773e2 100644 --- a/cf/test/test_Field.py +++ b/cf/test/test_Field.py @@ -2859,6 +2859,30 @@ def test_Field_pad_missing(self): self.assertEqual(g.shape, (6, 11)) self.assertTrue(g[5, :].mask.all()) + def test_Field_cyclic_iscyclic(self): + """Test the `cyclic` and `iscyclic` Field methods.""" + f1 = cf.example_field(1) # no cyclic axes + f2 = cf.example_field(2) # one cyclic axis, 'domainaxis2' ('X') + + # Getting + self.assertEqual(f1.cyclic(), set()) + self.assertFalse(f1.iscyclic("X")) + self.assertFalse(f1.iscyclic("Y")) + self.assertFalse(f1.iscyclic("Z")) + self.assertFalse(f1.iscyclic("T")) + self.assertEqual(f2.cyclic(), set(("domainaxis2",))) + self.assertTrue(f2.iscyclic("X")) + self.assertFalse(f2.iscyclic("Y")) + self.assertFalse(f2.iscyclic("Z")) + self.assertFalse(f2.iscyclic("T")) + + # 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",))) + self.assertTrue(f2.iscyclic("X")) + if __name__ == "__main__": print("Run date:", datetime.datetime.now())