def test_RaggedIndexedContiguousArray_to_memory(self):
        """TODO DOCS."""
        compressed_data = cfdm.Data([
            280.0,
            281.0,
            279.0,
            278.0,
            279.5,
            281.0,
            282.0,
            278.0,
            279.0,
            277.5,
        ])

        index = cfdm.Index(data=[0, 0, 0, 0, 1, 1, 1, 1])

        cfdm.Count(data=[1, 3, 2, 2])

        r = cfdm.RaggedIndexedContiguousArray(
            compressed_data,
            shape=(2, 2, 3),
            size=12,
            ndim=3,
            index_variable=index,
            count_variable=index,
        )

        r.to_memory()
Exemple #2
0
    def test_netCDF_sample_dimension_groups(self):
        """Test sample dimension groups access NetCDF methods."""
        c = cfdm.Count()

        c.nc_set_sample_dimension("ncvar")

        with self.assertRaises(ValueError):
            c.nc_set_sample_dimension_groups(["/forecast"])

        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        attrs = c.nc_clear_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        c.nc_set_sample_dimension_groups(["forecast", "model"])
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ("forecast", "model"))
        self.assertEqual(c.nc_get_sample_dimension(), "/forecast/model/ncvar")

        attrs = c.nc_clear_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ("forecast", "model"))

        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)
        self.assertEqual(c.nc_get_sample_dimension(), "ncvar")

        c.nc_set_sample_dimension("ncvar")
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ())

        c.nc_set_sample_dimension("/ncvar")
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        c.nc_set_sample_dimension("/forecast/model/ncvar")
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ("forecast", "model"))

        c.nc_del_sample_dimension()
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        with self.assertRaises(ValueError):
            c.nc_set_sample_dimension_groups(["forecast", "model"])
Exemple #3
0
    def test_DSG_contiguous(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        f = self.c.copy()

        self.assertEqual(len(f), 2)

        # Select the specific humidity field
        q = [g for g in f
             if g.get_property('standard_name') == 'specific_humidity'][0]

        self.assertTrue(q._equals(self.a, q.data.array))

        cfdm.write(f, tempfile)
        g = cfdm.read(tempfile)

        self.assertEqual(len(g), len(f))

        for i in range(len(f)):
            self.assertTrue(g[i].equals(f[i], verbose=3))

        # ------------------------------------------------------------
        # Test creation
        # ------------------------------------------------------------
        # Define the ragged array values
        ragged_array = numpy.array([280, 282.5, 281, 279, 278, 279.5],
                                   dtype='float32')

        # Define the count array values
        count_array = [2, 4]

        # Create the count variable
        count_variable = cfdm.Count(data=cfdm.Data(count_array))
        count_variable.set_property('long_name',
                                    'number of obs for this timeseries')

        # Create the contiguous ragged array object
        array = cfdm.RaggedContiguousArray(
                         compressed_array=cfdm.NumpyArray(ragged_array),
                         shape=(2, 4), size=8, ndim=2,
                         count_variable=count_variable)

        # Create the field construct with the domain axes and the ragged
        # array
        tas = cfdm.Field()
        tas.set_properties({'standard_name': 'air_temperature',
                            'units': 'K',
                            'featureType': 'timeSeries'})

        # Create the domain axis constructs for the uncompressed array
        X = tas.set_construct(cfdm.DomainAxis(4))
        Y = tas.set_construct(cfdm.DomainAxis(2))

        # Set the data for the field
        tas.set_data(cfdm.Data(array), axes=[Y, X])

        cfdm.write(tas, tempfile)
Exemple #4
0
    def test_DSG_create_contiguous(self):
        """Test the creation of a contiguous ragged array."""
        # Define the ragged array values
        ragged_array = numpy.array([1, 3, 4, 3, 6], dtype="float32")
        # Define the count array values
        count_array = [2, 3]

        # Initialise the count variable
        count_variable = cfdm.Count(data=cfdm.Data(count_array))
        count_variable.set_property(
            "long_name", "number of obs for this timeseries"
        )

        # Initialise the contiguous ragged array object
        array = cfdm.RaggedContiguousArray(
            compressed_array=cfdm.Data(ragged_array),
            shape=(2, 3),
            size=6,
            ndim=2,
            count_variable=count_variable,
        )

        # Initialize the auxiliary coordinate construct with the
        # ragged array and set some properties
        z = cfdm.AuxiliaryCoordinate(
            data=cfdm.Data(array),
            properties={
                "standard_name": "height",
                "units": "km",
                "positive": "up",
            },
        )

        self.assertTrue(
            (
                z.data.array
                == numpy.ma.masked_array(
                    data=[[1.0, 3.0, 99], [4.0, 3.0, 6.0]],
                    mask=[[False, False, True], [False, False, False]],
                    fill_value=1e20,
                    dtype="float32",
                )
            ).all()
        )

        self.assertEqual(z.data.get_compression_type(), "ragged contiguous")

        self.assertTrue(
            (
                z.data.compressed_array
                == numpy.array([1.0, 3.0, 4.0, 3.0, 6.0], dtype="float32")
            ).all()
        )

        self.assertTrue(
            (z.data.get_count().data.array == numpy.array([2, 3])).all()
        )
    def setUp(self):
        # Disable log messages to silence expected warnings
        cfdm.log_level('DISABLE')
        # Note: to enable all messages for given methods, lines or calls (those
        # without a 'verbose' option to do the same) e.g. to debug them, wrap
        # them (for methods, start-to-end internally) as follows:
        # cfdm.log_level('DEBUG')
        # < ... test code ... >
        # cfdm.log_level('DISABLE')

        compressed_data = cfdm.Data([280.0, 281.0, 279.0, 278.0, 279.5])
        count = cfdm.Count(data=[1, 3])
        self.r = cfdm.RaggedContiguousArray(compressed_data,
                                            shape=(2, 3),
                                            size=6,
                                            ndim=2,
                                            count_variable=count)
Exemple #6
0
    def test_DSG_create_contiguous(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        # Define the ragged array values
        ragged_array = numpy.array([1, 3, 4, 3, 6], dtype='float32')
        # Define the count array values
        count_array = [2, 3]

        # Initialise the count variable
        count_variable = cfdm.Count(data=cfdm.Data(count_array))
        count_variable.set_property('long_name',
                                    'number of obs for this timeseries')

        # Initialise the contiguous ragged array object
        array = cfdm.RaggedContiguousArray(
            compressed_array=cfdm.Data(ragged_array),
            shape=(2, 3), size=6, ndim=2,
            count_variable=count_variable)

        # Initialize the auxiliary coordinate construct with the
        # ragged array and set some properties
        z = cfdm.AuxiliaryCoordinate(
            data=cfdm.Data(array),
            properties={'standard_name': 'height',
                        'units': 'km',
                        'positive': 'up'})

        self.assertTrue((z.data.array == numpy.ma.masked_array(
            data=[[1.0, 3.0, 99],
                  [4.0, 3.0, 6.0]],
            mask=[[False, False,  True],
                  [False, False, False]],
            fill_value=1e+20,
            dtype='float32')).all())

        self.assertEqual(z.data.get_compression_type(), 'ragged contiguous')

        self.assertTrue((z.data.compressed_array == numpy.array(
            [1., 3., 4., 3., 6.], dtype='float32')).all())

        self.assertTrue((z.data.get_count().data.array == numpy.array(
            [2, 3])).all())
Exemple #7
0
    def test_netCDF_variable_dimension(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        f = cfdm.Field()

        f.nc_set_variable('qwerty')
        self.assertTrue(f.nc_has_variable())
        self.assertTrue(f.nc_get_variable() == 'qwerty')
        self.assertTrue(f.nc_get_variable(default=None) == 'qwerty')
        self.assertTrue(f.nc_del_variable() == 'qwerty')
        self.assertFalse(f.nc_has_variable())
        self.assertTrue(f.nc_get_variable(default=None) == None)
        self.assertTrue(f.nc_del_variable(default=None) == None)

        d = cfdm.DomainAxis()

        d.nc_set_dimension('qwerty')
        self.assertTrue(d.nc_has_dimension())
        self.assertTrue(d.nc_get_dimension() == 'qwerty')
        self.assertTrue(d.nc_get_dimension(default=None) == 'qwerty')
        self.assertTrue(d.nc_del_dimension() == 'qwerty')
        self.assertFalse(d.nc_has_dimension())
        self.assertTrue(d.nc_get_dimension(default=None) == None)
        self.assertTrue(d.nc_del_dimension(default=None) == None)

        d = cfdm.Count()

        d.nc_set_sample_dimension('qwerty')
        self.assertTrue(d.nc_has_sample_dimension())
        self.assertTrue(d.nc_get_sample_dimension() == 'qwerty')
        self.assertTrue(d.nc_get_sample_dimension(default=None) == 'qwerty')
        self.assertTrue(d.nc_del_sample_dimension() == 'qwerty')
        self.assertFalse(d.nc_has_sample_dimension())
        self.assertTrue(d.nc_get_sample_dimension(default=None) == None)
        self.assertTrue(d.nc_del_sample_dimension(default=None) == None)
Exemple #8
0
    def test_netCDF_variable_dimension(self):
        """Test variable and dimension access NetCDF methods."""
        f = cfdm.Field()

        f.nc_set_variable("qwerty")
        self.assertTrue(f.nc_has_variable())
        self.assertEqual(f.nc_get_variable(), "qwerty")
        self.assertEqual(f.nc_get_variable(default=None), "qwerty")
        self.assertEqual(f.nc_del_variable(), "qwerty")
        self.assertFalse(f.nc_has_variable())
        self.assertIsNone(f.nc_get_variable(default=None))
        self.assertIsNone(f.nc_del_variable(default=None))

        f.nc_set_variable("/ncvar")
        self.assertEqual(f.nc_get_variable(), "ncvar")

        f.nc_set_variable("/ncvar/qwerty")
        self.assertEqual(f.nc_get_variable(), "/ncvar/qwerty")

        for nc_var_name in self.nc_grouped_variable_names:
            with self.assertRaises(ValueError):
                f.nc_set_variable(nc_var_name)

        d = cfdm.DomainAxis()

        d.nc_set_dimension("qwerty")
        self.assertTrue(d.nc_has_dimension())
        self.assertEqual(d.nc_get_dimension(), "qwerty")
        self.assertEqual(d.nc_get_dimension(default=None), "qwerty")
        self.assertEqual(d.nc_del_dimension(), "qwerty")
        self.assertFalse(d.nc_has_dimension())
        self.assertIsNone(d.nc_get_dimension(default=None))
        self.assertIsNone(d.nc_del_dimension(default=None))

        d.nc_set_dimension("/ncdim")
        self.assertEqual(d.nc_get_dimension(), "ncdim")

        d.nc_set_dimension("/ncdim/qwerty")
        self.assertEqual(d.nc_get_dimension(), "/ncdim/qwerty")

        for nc_dim_name in self.nc_grouped_dimension_names:
            with self.assertRaises(ValueError):
                d.nc_set_dimension(nc_dim_name)

        d = cfdm.Count()

        d.nc_set_sample_dimension("qwerty")
        self.assertTrue(d.nc_has_sample_dimension())
        self.assertEqual(d.nc_get_sample_dimension(), "qwerty")
        self.assertEqual(d.nc_get_sample_dimension(default=None), "qwerty")
        self.assertEqual(d.nc_del_sample_dimension(), "qwerty")
        self.assertFalse(d.nc_has_sample_dimension())
        self.assertIsNone(d.nc_get_sample_dimension(default=None))
        self.assertIsNone(d.nc_del_sample_dimension(default=None))

        d.nc_set_sample_dimension("/ncdim")
        self.assertEqual(d.nc_get_sample_dimension(), "ncdim")

        d.nc_set_sample_dimension("/ncdim/qwerty")
        self.assertEqual(d.nc_get_sample_dimension(), "/ncdim/qwerty")

        for nc_dim_name in self.nc_grouped_dimension_names:
            with self.assertRaises(ValueError):
                d.nc_set_sample_dimension(nc_dim_name)

        # ------------------------------------------------------------
        # Global attributes
        # ------------------------------------------------------------
        # values keyword
        f = cfdm.Field()

        f.nc_set_global_attribute("Conventions", "CF-1.8")
        f.nc_set_global_attribute("project")
        f.nc_set_global_attribute("foo")
        f.set_property("Conventions", "Y")
        f.set_property("project", "X")
        self.assertEqual(
            f.nc_global_attributes(values=True),
            {"Conventions": "CF-1.8", "project": "X", "foo": None},
        )

        f = cfdm.Field()
        self.assertEqual(f.nc_clear_global_attributes(), {})

        f.nc_set_global_attribute("Conventions")
        f.nc_set_global_attribute("project", "X")
        self.assertEqual(
            f.nc_global_attributes(), {"Conventions": None, "project": "X"}
        )

        f.nc_set_global_attribute("project")
        f.nc_set_global_attribute("comment", None)
        self.assertEqual(
            f.nc_global_attributes(),
            {"Conventions": None, "project": None, "comment": None},
        )

        self.assertEqual(
            f.nc_clear_global_attributes(),
            {"Conventions": None, "project": None, "comment": None},
        )
        self.assertEqual(f.nc_global_attributes(), {})

        f.nc_set_global_attribute("Conventions")
        f.nc_set_global_attribute("project")
        self.assertEqual(
            f.nc_global_attributes(), {"Conventions": None, "project": None}
        )

        _ = f.nc_clear_global_attributes()
        f.nc_set_global_attributes({})
        self.assertEqual(f.nc_global_attributes(), {})

        f.nc_set_global_attributes({"comment": 123}, copy=False)
        self.assertEqual(f.nc_global_attributes(), {"comment": 123})

        f.nc_set_global_attributes({"comment": None, "foo": "bar"})
        self.assertEqual(
            f.nc_global_attributes(), {"comment": None, "foo": "bar"}
        )

        f = cfdm.Field()
        f.set_properties({"foo": "bar", "comment": "variable comment"})
        f.nc_set_variable("tas")
        d = f.set_construct(cfdm.DomainAxis(2))
        f.set_data(cfdm.Data([8, 9]), axes=[d])

        f2 = f.copy()
        f2.nc_set_variable("ua")

        cfdm.write(
            [f, f2],
            tempfile1,
            file_descriptors={"comment": "global comment", "qwerty": "asdf"},
        )

        g = cfdm.read(tempfile1)
        self.assertEqual(len(g), 2)

        for x in g:
            self.assertEqual(
                x.properties(),
                {
                    "comment": "variable comment",
                    "foo": "bar",
                    "qwerty": "asdf",
                    "Conventions": "CF-" + cfdm.CF(),
                },
            )
            self.assertEqual(
                x.nc_global_attributes(),
                {
                    "comment": "global comment",
                    "qwerty": None,
                    "Conventions": None,
                },
            )

        cfdm.write(g, tempfile2)
        h = cfdm.read(tempfile2)
        for x, y in zip(h, g):
            self.assertEqual(x.properties(), y.properties())
            self.assertEqual(
                x.nc_global_attributes(), y.nc_global_attributes()
            )
            self.assertTrue(x.equals(y, verbose=3))
            self.assertTrue(y.equals(x, verbose=3))

        g[1].nc_set_global_attribute("comment", "different comment")
        cfdm.write(g, tempfile3)
        h = cfdm.read(tempfile3)
        for x, y in zip(h, g):
            self.assertEqual(x.properties(), y.properties())
            self.assertEqual(
                x.nc_global_attributes(),
                {"comment": None, "qwerty": None, "Conventions": None},
            )
            self.assertTrue(x.equals(y, verbose=3))
            self.assertTrue(y.equals(x, verbose=3))
Exemple #9
0
count_variable = T.data.get_count()
count_variable
print(count_variable.data.array)
cfdm.write(T, 'T_contiguous.nc')

import numpy
import cfdm

# Define the ragged array values
ragged_array = cfdm.Data([280, 281, 279, 278, 279.5])

# Define the count array values
count_array = [1, 4]

# Create the count variable
count_variable = cfdm.Count(data=cfdm.Data(count_array))
count_variable.set_property('long_name', 'number of obs for this timeseries')

# Create the contiguous ragged array object, specifying the
# uncompressed shape
array = cfdm.RaggedContiguousArray(
                 compressed_array=ragged_array,
                 shape=(2, 4), size=8, ndim=2,
                 count_variable=count_variable)

# Create the field construct with the domain axes and the ragged
# array
T = cfdm.Field()
T.set_properties({'standard_name': 'air_temperature',
                  'units': 'K',
                  'featureType': 'timeSeries'})
Exemple #10
0
    def test_DSG_contiguous(self):
        """TODO DOCS."""
        f = self.c.copy()

        self.assertEqual(len(f), 2)

        # Select the specific humidity field
        q = [
            g for g in f
            if g.get_property("standard_name") == "specific_humidity"
        ][0]

        self.assertTrue(q._equals(self.a, q.data.array))

        cfdm.write(f, tempfile)
        g = cfdm.read(tempfile)

        self.assertEqual(len(g), len(f))

        for i in range(len(f)):
            self.assertTrue(g[i].equals(f[i], verbose=3))

        # ------------------------------------------------------------
        # Test creation
        # ------------------------------------------------------------
        # Define the ragged array values
        ragged_array = numpy.array([280, 282.5, 281, 279, 278, 279.5],
                                   dtype="float32")

        # Define the count array values
        count_array = [2, 4]

        # Create the count variable
        count_variable = cfdm.Count(data=cfdm.Data(count_array))
        count_variable.set_property("long_name",
                                    "number of obs for this timeseries")

        # Create the contiguous ragged array object
        array = cfdm.RaggedContiguousArray(
            compressed_array=cfdm.NumpyArray(ragged_array),
            shape=(2, 4),
            size=8,
            ndim=2,
            count_variable=count_variable,
        )

        # Create the field construct with the domain axes and the ragged
        # array
        tas = cfdm.Field()
        tas.set_properties({
            "standard_name": "air_temperature",
            "units": "K",
            "featureType": "timeSeries",
        })

        # Create the domain axis constructs for the uncompressed array
        X = tas.set_construct(cfdm.DomainAxis(4))
        Y = tas.set_construct(cfdm.DomainAxis(2))

        # Set the data for the field
        tas.set_data(cfdm.Data(array), axes=[Y, X])

        cfdm.write(tas, tempfile)
Exemple #11
0
    def test_netCDF_sample_dimension_groups(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        c = cfdm.Count()

        c.nc_set_sample_dimension('ncvar')

        with self.assertRaises(ValueError):
            c.nc_set_sample_dimension_groups(['/forecast'])

        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        attrs = c.nc_clear_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        c.nc_set_sample_dimension_groups(['forecast', 'model'])
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ('forecast', 'model'))
        self.assertEqual(c.nc_get_sample_dimension(),
                         '/forecast/model/ncvar')

        attrs = c.nc_clear_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ('forecast', 'model'))

        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)
        self.assertEqual(c.nc_get_sample_dimension(), 'ncvar')

        c.nc_set_sample_dimension('ncvar')
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ())

        c.nc_set_sample_dimension('/ncvar')
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        c.nc_set_sample_dimension('/forecast/model/ncvar')
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertEqual(attrs, ('forecast', 'model'))

        c.nc_del_sample_dimension()
        attrs = c.nc_sample_dimension_groups()
        self.assertIsInstance(attrs, tuple)
        self.assertFalse(attrs)

        with self.assertRaises(ValueError):
            c.nc_set_sample_dimension_groups(['forecast', 'model'])
Exemple #12
0
    def test_netCDF_variable_dimension(self):
        if self.test_only and inspect.stack()[0][3] not in self.test_only:
            return

        f = cfdm.Field()

        f.nc_set_variable('qwerty')
        self.assertTrue(f.nc_has_variable())
        self.assertEqual(f.nc_get_variable(), 'qwerty')
        self.assertEqual(f.nc_get_variable(default=None), 'qwerty')
        self.assertEqual(f.nc_del_variable(), 'qwerty')
        self.assertFalse(f.nc_has_variable())
        self.assertIsNone(f.nc_get_variable(default=None))
        self.assertIsNone(f.nc_del_variable(default=None))

        f.nc_set_variable('/ncvar')
        self.assertEqual(f.nc_get_variable(), 'ncvar')

        f.nc_set_variable('/ncvar/qwerty')
        self.assertEqual(f.nc_get_variable(), '/ncvar/qwerty')

        with self.assertRaises(ValueError):
            f.nc_set_variable(None)

        with self.assertRaises(ValueError):
            f.nc_set_variable('/')

        with self.assertRaises(ValueError):
            f.nc_set_variable('group/ncvar')

        with self.assertRaises(ValueError):
            f.nc_set_variable('group/')

        with self.assertRaises(ValueError):
            f.nc_set_variable('group/ncvar/')

        with self.assertRaises(ValueError):
            f.nc_set_variable('/group/ncvar/')

        d = cfdm.DomainAxis()

        d.nc_set_dimension('qwerty')
        self.assertTrue(d.nc_has_dimension())
        self.assertEqual(d.nc_get_dimension(), 'qwerty')
        self.assertEqual(d.nc_get_dimension(default=None), 'qwerty')
        self.assertEqual(d.nc_del_dimension(), 'qwerty')
        self.assertFalse(d.nc_has_dimension())
        self.assertIsNone(d.nc_get_dimension(default=None))
        self.assertIsNone(d.nc_del_dimension(default=None))

        d.nc_set_dimension('/ncdim')
        self.assertEqual(d.nc_get_dimension(), 'ncdim')

        d.nc_set_dimension('/ncdim/qwerty')
        self.assertEqual(d.nc_get_dimension(), '/ncdim/qwerty')

        with self.assertRaises(ValueError):
            d.nc_set_dimension(None)

        with self.assertRaises(ValueError):
            d.nc_set_dimension('/')

        with self.assertRaises(ValueError):
            d.nc_set_dimension('group/ncdim')

        with self.assertRaises(ValueError):
            d.nc_set_dimension('group/')

        with self.assertRaises(ValueError):
            d.nc_set_dimension('group/ncdim/')

        with self.assertRaises(ValueError):
            d.nc_set_dimension('/group/ncdim/')

        d = cfdm.Count()

        d.nc_set_sample_dimension('qwerty')
        self.assertTrue(d.nc_has_sample_dimension())
        self.assertEqual(d.nc_get_sample_dimension(), 'qwerty')
        self.assertEqual(d.nc_get_sample_dimension(default=None), 'qwerty')
        self.assertEqual(d.nc_del_sample_dimension(), 'qwerty')
        self.assertFalse(d.nc_has_sample_dimension())
        self.assertIsNone(d.nc_get_sample_dimension(default=None))
        self.assertIsNone(d.nc_del_sample_dimension(default=None))

        d.nc_set_sample_dimension('/ncdim')
        self.assertEqual(d.nc_get_sample_dimension(), 'ncdim')

        d.nc_set_sample_dimension('/ncdim/qwerty')
        self.assertEqual(d.nc_get_sample_dimension(), '/ncdim/qwerty')

        with self.assertRaises(ValueError):
            d.nc_set_sample_dimension(None)

        with self.assertRaises(ValueError):
            d.nc_set_sample_dimension('/')

        with self.assertRaises(ValueError):
            d.nc_set_sample_dimension('group/ncdim')

        with self.assertRaises(ValueError):
            d.nc_set_sample_dimension('group/')

        with self.assertRaises(ValueError):
            d.nc_set_sample_dimension('group/ncdim/')

        with self.assertRaises(ValueError):
            d.nc_set_sample_dimension('/group/ncdim/')

        # ------------------------------------------------------------
        # Global attributes
        # ------------------------------------------------------------
        # values keyword
        f = cfdm.Field()

        f.nc_set_global_attribute('Conventions', 'CF-1.8')
        f.nc_set_global_attribute('project')
        f.nc_set_global_attribute('foo')
        f.set_property('Conventions', 'Y')
        f.set_property('project', 'X')
        self.assertEqual(f.nc_global_attributes(values=True),
                         {'Conventions': 'CF-1.8',
                          'project': 'X',
                          'foo': None})

        f = cfdm.Field()
        self.assertEqual(f.nc_clear_global_attributes(), {})

        f.nc_set_global_attribute('Conventions')
        f.nc_set_global_attribute('project', 'X')
        self.assertEqual(f.nc_global_attributes(), {'Conventions': None,
                                                    'project': 'X'})

        f.nc_set_global_attribute('project')
        f.nc_set_global_attribute('comment', None)
        self.assertEqual(f.nc_global_attributes(), {'Conventions': None,
                                                    'project': None,
                                                    'comment': None})

        self.assertEqual(f.nc_clear_global_attributes(), {'Conventions': None,
                                                          'project': None,
                                                          'comment': None})
        self.assertEqual(f.nc_global_attributes(), {})

        f.nc_set_global_attribute('Conventions')
        f.nc_set_global_attribute('project')
        self.assertEqual(f.nc_global_attributes(), {'Conventions': None,
                                                    'project': None})

        _ = f.nc_clear_global_attributes()
        f.nc_set_global_attributes({})
        self.assertEqual(f.nc_global_attributes(), {})

        f.nc_set_global_attributes({'comment': 123}, copy=False)
        self.assertEqual(f.nc_global_attributes(), {'comment': 123})

        f.nc_set_global_attributes({'comment': None, 'foo': 'bar'})
        self.assertEqual(f.nc_global_attributes(), {'comment': None,
                                                    'foo': 'bar'})

        f = cfdm.Field()
        f.set_properties({'foo': 'bar', 'comment': 'variable comment'})
        f.nc_set_variable('tas')
        d = f.set_construct(cfdm.DomainAxis(2))
        f.set_data(cfdm.Data([8, 9]), axes=[d])

        f2 = f.copy()
        f2.nc_set_variable('ua')

        cfdm.write([f, f2], tempfile1,
                   file_descriptors={'comment': 'global comment',
                                     'qwerty': 'asdf'})

        g = cfdm.read(tempfile1)
        self.assertEqual(len(g), 2)

        for x in g:
            self.assertEqual(x.properties(), {'comment': 'variable comment',
                                              'foo': 'bar',
                                              'qwerty': 'asdf',
                                              'Conventions': 'CF-'+cfdm.CF()})
            self.assertEqual(x.nc_global_attributes(),
                             {'comment': 'global comment',
                              'qwerty': None,
                              'Conventions': None})

        cfdm.write(g, tempfile2)
        h = cfdm.read(tempfile2)
        for x, y in zip(h, g):
            self.assertEqual(x.properties(), y.properties())
            self.assertEqual(x.nc_global_attributes(),
                             y.nc_global_attributes())
            self.assertTrue(x.equals(y, verbose=3))
            self.assertTrue(y.equals(x, verbose=3))

        g[1].nc_set_global_attribute('comment', 'different comment')
        cfdm.write(g, tempfile3)
        h = cfdm.read(tempfile3)
        for x, y in zip(h, g):
            self.assertEqual(x.properties(), y.properties())
            self.assertEqual(x.nc_global_attributes(), {'comment': None,
                                                        'qwerty': None,
                                                        'Conventions': None})
            self.assertTrue(x.equals(y, verbose=3))
            self.assertTrue(y.equals(x, verbose=3))