@@ -759,7 +759,7 @@ def _create_cf_dimensions(self, cube, dimension_names, unlimited_dimensions=None
759759 # used for a different one
760760 pass
761761 else :
762- dim_name = self ._get_coord_variable_name (cube , coord )
762+ dim_name = self ._get_element_variable_name (cube , coord )
763763 unlimited_dim_names .append (dim_name )
764764
765765 for dim_name in dimension_names :
@@ -1365,7 +1365,7 @@ def record_dimension(names_list, dim_name, length, matching_coords=None):
13651365 if dim_name is None :
13661366 # Not already present : create a unique dimension name
13671367 # from the coord.
1368- dim_name = self ._get_coord_variable_name (cube , coord )
1368+ dim_name = self ._get_element_variable_name (cube , coord )
13691369 # Disambiguate if it has the same name as an
13701370 # existing dimension.
13711371 # OR if it matches an existing file variable name.
@@ -1541,38 +1541,14 @@ def _create_cf_bounds(self, coord, cf_var, cf_name, /, *, compression_kwargs=Non
15411541 )
15421542 self ._lazy_stream_data (data = bounds , cf_var = cf_var_bounds )
15431543
1544- def _get_cube_variable_name (self , cube ):
1545- """Return a CF-netCDF variable name for the given cube.
1546-
1547- Parameters
1548- ----------
1549- cube : :class:`iris.cube.Cube`
1550- An instance of a cube for which a CF-netCDF variable
1551- name is required.
1552-
1553- Returns
1554- -------
1555- str
1556- A CF-netCDF variable name as a string.
1557-
1558- """
1559- if cube .var_name is not None :
1560- cf_name = cube .var_name
1561- else :
1562- # Convert to lower case and replace whitespace by underscores.
1563- cf_name = "_" .join (cube .name ().lower ().split ())
1564-
1565- cf_name = self .cf_valid_var_name (cf_name )
1566- return cf_name
1567-
1568- def _get_coord_variable_name (self , cube_or_mesh , coord ):
1569- """Return a CF-netCDF variable name for a given coordinate-like element.
1544+ def _get_element_variable_name (self , cube_or_mesh , element ):
1545+ """Return a CF-netCDF variable name for a given coordinate-like element, or cube.
15701546
15711547 Parameters
15721548 ----------
15731549 cube_or_mesh : :class:`iris.cube.Cube` or :class:`iris.mesh.MeshXY`
15741550 The Cube or Mesh being saved to the netCDF file.
1575- coord : :class:`iris.coords._DimensionalMetadata`
1551+ element : :class:`iris.coords._DimensionalMetadata` | :class:``iris.cube.Cube` `
15761552 An instance of a coordinate (or similar), for which a CF-netCDF
15771553 variable name is required.
15781554
@@ -1592,17 +1568,21 @@ def _get_coord_variable_name(self, cube_or_mesh, coord):
15921568 cube = None
15931569 mesh = cube_or_mesh
15941570
1595- if coord .var_name is not None :
1596- cf_name = coord .var_name
1571+ if element .var_name is not None :
1572+ cf_name = element .var_name
1573+ elif isinstance (element , Cube ):
1574+ # Make name for a Cube without a var_name.
1575+ cf_name = "_" .join (element .name ().lower ().split ())
15971576 else :
1598- name = coord .standard_name or coord .long_name
1577+ # Make name for a Coord-like element without a var_name
1578+ name = element .standard_name or element .long_name
15991579 if not name or set (name ).intersection (string .whitespace ):
16001580 # We need to invent a name, based on its associated dimensions.
1601- if cube is not None and cube .coords ( coord ):
1602- # It is a regular cube coordinate .
1581+ if cube is not None and cube .elements ( element ):
1582+ # It is a regular cube elementinate .
16031583 # Auto-generate a name based on the dims.
16041584 name = ""
1605- for dim in cube .coord_dims (coord ):
1585+ for dim in cube .coord_dims (element ):
16061586 name += f"dim{ dim } "
16071587 # Handle scalar coordinate (dims == ()).
16081588 if not name :
@@ -1616,8 +1596,8 @@ def _get_coord_variable_name(self, cube_or_mesh, coord):
16161596
16171597 # At present, a location-coord cannot be nameless, as the
16181598 # MeshXY code relies on guess_coord_axis.
1619- assert isinstance (coord , Connectivity )
1620- location = coord .cf_role .split ("_" )[0 ]
1599+ assert isinstance (element , Connectivity )
1600+ location = element .cf_role .split ("_" )[0 ]
16211601 location_dim_attr = f"{ location } _dimension"
16221602 name = getattr (mesh , location_dim_attr )
16231603
@@ -1693,6 +1673,8 @@ def _create_mesh(self, mesh):
16931673 return cf_mesh_name
16941674
16951675 def _set_cf_var_attributes (self , cf_var , element ):
1676+ from iris .cube import Cube
1677+
16961678 # Deal with CF-netCDF units, and add the name+units properties.
16971679 if isinstance (element , iris .coords .Coord ):
16981680 # Fix "degree" units if needed.
@@ -1715,19 +1697,21 @@ def _set_cf_var_attributes(self, cf_var, element):
17151697 if element .units .calendar :
17161698 _setncattr (cf_var , "calendar" , str (element .units .calendar ))
17171699
1718- # Add any other custom coordinate attributes.
1719- for name in sorted (element .attributes ):
1720- value = element .attributes [name ]
1700+ if not isinstance (element , Cube ):
1701+ # Add any other custom coordinate attributes.
1702+ # N.B. not Cube, which has specific handling in _create_cf_data_variable
1703+ for name in sorted (element .attributes ):
1704+ value = element .attributes [name ]
17211705
1722- if name == "STASH" :
1723- # Adopting provisional Metadata Conventions for representing MO
1724- # Scientific Data encoded in NetCDF Format.
1725- name = "um_stash_source"
1726- value = str (value )
1706+ if name == "STASH" :
1707+ # Adopting provisional Metadata Conventions for representing MO
1708+ # Scientific Data encoded in NetCDF Format.
1709+ name = "um_stash_source"
1710+ value = str (value )
17271711
1728- # Don't clobber existing attributes.
1729- if not hasattr (cf_var , name ):
1730- _setncattr (cf_var , name , value )
1712+ # Don't clobber existing attributes.
1713+ if not hasattr (cf_var , name ):
1714+ _setncattr (cf_var , name , value )
17311715
17321716 def _create_generic_cf_array_var (
17331717 self ,
@@ -1739,6 +1723,7 @@ def _create_generic_cf_array_var(
17391723 element_dims = None ,
17401724 fill_value = None ,
17411725 compression_kwargs = None ,
1726+ is_dataless = False ,
17421727 ):
17431728 """Create theCF-netCDF variable given dimensional_metadata.
17441729
@@ -1791,7 +1776,7 @@ def _create_generic_cf_array_var(
17911776
17921777 # Work out the var-name to use.
17931778 # N.B. the only part of this routine that may use a mesh _or_ a cube.
1794- cf_name = self ._get_coord_variable_name (cube_or_mesh , element )
1779+ cf_name = self ._get_element_variable_name (cube_or_mesh , element )
17951780 while cf_name in self ._dataset .variables :
17961781 cf_name = self ._increment_name (cf_name )
17971782
@@ -1804,10 +1789,13 @@ def _create_generic_cf_array_var(
18041789 # Get the data values, in a way which works for any element type, as
18051790 # all are subclasses of _DimensionalMetadata.
18061791 # (e.g. =points if a coord, =data if an ancillary, etc)
1807- data = element ._core_values ()
1792+ if isinstance (element , Cube ):
1793+ data = element .core_data ()
1794+ else :
1795+ data = element ._core_values ()
18081796
18091797 # This compression contract is *not* applicable to a mesh.
1810- if cube and cube .shape != data .shape :
1798+ if cube is not None and data is not None and cube .shape != data .shape :
18111799 compression_kwargs = {}
18121800
18131801 if np .issubdtype (data .dtype , np .str_ ):
@@ -1837,11 +1825,13 @@ def _create_generic_cf_array_var(
18371825 # Convert data from an array of strings into a character array
18381826 # with an extra string-length dimension.
18391827 if len (element_dims ) == 1 :
1828+ # Scalar variable (only has string dimension).
18401829 data_first = data [0 ]
18411830 if is_lazy_data (data_first ):
18421831 data_first = dask .compute (data_first )
18431832 data = list ("%- *s" % (string_dimension_depth , data_first ))
18441833 else :
1834+ # NOTE: at present, can't do this lazily??
18451835 orig_shape = data .shape
18461836 new_shape = orig_shape + (string_dimension_depth ,)
18471837 new_data = np .zeros (new_shape , cf_var .dtype )
@@ -1850,7 +1840,7 @@ def _create_generic_cf_array_var(
18501840 new_data [index_slice ] = list (
18511841 "%- *s" % (string_dimension_depth , data [index ])
18521842 )
1853- data = new_data
1843+ data = new_data
18541844 else :
18551845 # A normal (numeric) variable.
18561846 # ensure a valid datatype for the file format.
@@ -1887,7 +1877,8 @@ def _create_generic_cf_array_var(
18871877 )
18881878
18891879 # Add the data to the CF-netCDF variable.
1890- self ._lazy_stream_data (data = data , cf_var = cf_var )
1880+ if not is_dataless :
1881+ self ._lazy_stream_data (data = data , cf_var = cf_var )
18911882
18921883 # Add names + units
18931884 self ._set_cf_var_attributes (cf_var , element )
@@ -2238,9 +2229,9 @@ def _create_cf_grid_mapping(self, cube, cf_var_cube):
22382229 cfvar = self ._name_coord_map .name (coord )
22392230 if not cfvar :
22402231 # not found - create and store it:
2241- cfvar = self ._get_coord_variable_name (cube , coord )
2232+ cfvar = self ._get_element_variable_name (cube , coord )
22422233 self ._name_coord_map .append (
2243- cfvar , self ._get_coord_variable_name (cube , coord )
2234+ cfvar , self ._get_element_variable_name (cube , coord )
22442235 )
22452236 cfvar_names .append (cfvar )
22462237
@@ -2383,32 +2374,43 @@ def set_packing_ncattrs(cfvar):
23832374 if add_offset :
23842375 _setncattr (cfvar , "add_offset" , add_offset )
23852376
2386- cf_name = self ._get_cube_variable_name (cube )
2387- while cf_name in self ._dataset .variables :
2388- cf_name = self ._increment_name (cf_name )
2389-
2377+ # cf_name = self._get_element_variable_name(cube_or_mesh=None, element=cube)
2378+ # while cf_name in self._dataset.variables:
2379+ # cf_name = self._increment_name(cf_name)
2380+ #
2381+ # cf_var = self._dataset.createVariable(
2382+ # cf_name, dtype, dimension_names, fill_value=fill_value, **kwargs
2383+ # )
23902384 # Create the cube CF-netCDF data variable with data payload.
2391- cf_var = self ._dataset .createVariable (
2392- cf_name , dtype , dimension_names , fill_value = fill_value , ** kwargs
2385+ cf_name = self ._create_generic_cf_array_var (
2386+ cube ,
2387+ dimension_names ,
2388+ cube ,
2389+ element_dims = dimension_names ,
2390+ fill_value = fill_value ,
2391+ compression_kwargs = kwargs ,
2392+ is_dataless = is_dataless ,
23932393 )
2394+ cf_var = self ._dataset .variables [cf_name ]
23942395
23952396 if not is_dataless :
23962397 set_packing_ncattrs (cf_var )
2397- self ._lazy_stream_data (data = data , cf_var = cf_var )
2398-
2399- if cube .standard_name :
2400- _setncattr (cf_var , "standard_name" , cube .standard_name )
2401-
2402- if cube .long_name :
2403- _setncattr (cf_var , "long_name" , cube .long_name )
2404-
2405- if cube .units .is_udunits ():
2406- _setncattr (cf_var , "units" , str (cube .units ))
2407-
2408- # Add the CF-netCDF calendar attribute.
2409- if cube .units .calendar :
2410- _setncattr (cf_var , "calendar" , cube .units .calendar )
24112398
2399+ # if cube.standard_name:
2400+ # _setncattr(cf_var, "standard_name", cube.standard_name)
2401+ #
2402+ # if cube.long_name:
2403+ # _setncattr(cf_var, "long_name", cube.long_name)
2404+ #
2405+ # if cube.units.is_udunits():
2406+ # _setncattr(cf_var, "units", str(cube.units))
2407+ #
2408+ # # Add the CF-netCDF calendar attribute.
2409+ # if cube.units.calendar:
2410+ # _setncattr(cf_var, "calendar", cube.units.calendar)
2411+
2412+ # Set attributes: NB this part is cube-specific (not the same for components)
2413+ # - therefore 'set_cf_var_attributes' doesn't set attributes if element is a Cube
24122414 if iris .FUTURE .save_split_attrs :
24132415 attr_names = cube .attributes .locals .keys ()
24142416 else :
0 commit comments