cfgrib icon indicating copy to clipboard operation
cfgrib copied to clipboard

Functionality Not Enabled Error When Opening GEM GRIB Files

Open edrewitz opened this issue 5 months ago • 5 comments

What happened?

Hi! I was trying to open a file that has GEM model data after downloading it with the following code:

import xarray as xr

ds = xr.open_dataset(f"GEM GLOBAL/ABSV_ISBL_200/CMC_glb_ABSV_ISBL_200_latlon.15x.15_2025091712_P000.grib2", engine='cfgrib')

ds['absv'].values

I got a "Functionality Not Enabled Error" when trying to look at the values in the array corresponding to the variable key. This has only been an issue so far with the GEM Global. I am not able to reproduce this issue for other models like the GFS or the RTMA etc so far. I've been using the same environment when working with other models.

What are the steps to reproduce the bug?

  1. Download a file for the GEM Global from https://dd.weather.gc.ca/

  2. Try opening the file in xarray with engine='cfgrib'

  3. Try inspecting the data array for the variable (e.g. ds['absv'].values)

Version

0.9.15.0

Platform (OS and architecture)

Windows 64

Relevant log output

---------------------------------------------------------------------------
FunctionalityNotEnabledError              Traceback (most recent call last)
Cell In[3], line 1
----> 1 ds['absv'].values

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\dataarray.py:797, in DataArray.values(self)
    784 @property
    785 def values(self) -> np.ndarray:
    786     """
    787     The array's data converted to numpy.ndarray.
    788 
   (...)    795     to this array may be reflected in the DataArray as well.
    796     """
--> 797     return self.variable.values

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\variable.py:556, in Variable.values(self)
    553 @property
    554 def values(self) -> np.ndarray:
    555     """The variable's data as a numpy.ndarray"""
--> 556     return _as_array_or_item(self._data)

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\variable.py:336, in _as_array_or_item(data)
    322 def _as_array_or_item(data):
    323     """Return the given values as a numpy array, or as an individual item if
    324     it's a 0d datetime64 or timedelta64 array.
    325 
   (...)    334     TODO: remove this (replace with np.asarray) once these issues are fixed
    335     """
--> 336     data = np.asarray(data)
    337     if data.ndim == 0:
    338         kind = data.dtype.kind

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\indexing.py:577, in ExplicitlyIndexed.__array__(self, dtype, copy)
    572 def __array__(
    573     self, dtype: np.typing.DTypeLike = None, /, *, copy: bool | None = None
    574 ) -> np.ndarray:
    575     # Leave casting to an array up to the underlying array type.
    576     if Version(np.__version__) >= Version("2.0.0"):
--> 577         return np.asarray(self.get_duck_array(), dtype=dtype, copy=copy)
    578     else:
    579         return np.asarray(self.get_duck_array(), dtype=dtype)

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\indexing.py:943, in MemoryCachedArray.get_duck_array(self)
    942 def get_duck_array(self):
--> 943     duck_array = self.array.get_duck_array()
    944     # ensure the array object is cached in-memory
    945     self.array = as_indexable(duck_array)

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\indexing.py:897, in CopyOnWriteArray.get_duck_array(self)
    896 def get_duck_array(self):
--> 897     return self.array.get_duck_array()

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\indexing.py:737, in LazilyIndexedArray.get_duck_array(self)
    734 from xarray.backends.common import BackendArray
    736 if isinstance(self.array, BackendArray):
--> 737     array = self.array[self.key]
    738 else:
    739     array = apply_indexer(self.array, self.key)

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\xarray_plugin.py:163, in CfGribArrayWrapper.__getitem__(self, key)
    159 def __getitem__(
    160     self,
    161     key: xr.core.indexing.ExplicitIndexer,
    162 ) -> np.ndarray:
--> 163     return xr.core.indexing.explicit_indexing_adapter(
    164         key, self.shape, xr.core.indexing.IndexingSupport.BASIC, self._getitem
    165     )

File ~\miniconda3\envs\wxdata\Lib\site-packages\xarray\core\indexing.py:1129, in explicit_indexing_adapter(key, shape, indexing_support, raw_indexing_method)
   1107 """Support explicit indexing by delegating to a raw indexing method.
   1108 
   1109 Outer and/or vectorized indexers are supported by indexing a second time
   (...)   1126 Indexing result, in the form of a duck numpy-array.
   1127 """
   1128 raw_key, numpy_indices = decompose_indexer(key, shape, indexing_support)
-> 1129 result = raw_indexing_method(raw_key.tuple)
   1130 if numpy_indices.tuple:
   1131     # index the loaded duck array
   1132     indexable = as_indexable(result)

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\xarray_plugin.py:172, in CfGribArrayWrapper._getitem(self, key)
    167 def _getitem(
    168     self,
    169     key: T.Tuple[T.Any, ...],
    170 ) -> np.ndarray:
    171     with self.datastore.lock:
--> 172         return self.array[key]

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\dataset.py:374, in OnDiskArray.__getitem__(self, item)
    372     # NOTE: fill a single field as found in the message
    373     message = self.index.get_field(message_ids[0])  # type: ignore
--> 374     values = get_values_in_order(message, array_field[tuple(array_field_indexes)].shape)
    375     array_field.__getitem__(tuple(array_field_indexes)).flat[:] = values
    377 array = np.asarray(array_field[(Ellipsis,) + item[-self.geo_ndim :]])

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\dataset.py:329, in get_values_in_order(message, shape)
    326 def get_values_in_order(message, shape):
    327     # type: (abc.Field, T.Tuple[int]) -> np.ndarray
    328     # inform the data provider to return missing values as missing_value
--> 329     values = message["values"]
    330     # for 2D array (lat/lon) re-arrange if alternative row scanning
    331     if len(shape) == 2 and message.get("alternativeRowScanning", False):

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\messages.py:247, in ComputedKeysAdapter.__getitem__(self, item)
    245     return getter(self)
    246 else:
--> 247     return self.context[item]

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\messages.py:169, in Message.__getitem__(self, item)
    167     raise ValueError("key type not supported %r" % key_type_text)
    168 key_type = KEY_TYPES[key_type_text]
--> 169 return self.message_get(key, key_type=key_type)

File ~\miniconda3\envs\wxdata\Lib\site-packages\cfgrib\messages.py:132, in Message.message_get(self, item, key_type, default)
    130 try:
    131     if eccodes.codes_get_size(self.codes_id, item) > 1:
--> 132         values = eccodes.codes_get_array(self.codes_id, item, key_type)
    133     else:
    134         values = [eccodes.codes_get(self.codes_id, item, key_type)]

File ~\miniconda3\envs\wxdata\Lib\site-packages\gribapi\gribapi.py:2028, in grib_get_array(msgid, key, ktype)
   2026     result = grib_get_long_array(msgid, key)
   2027 elif ktype is float or ktype is np.float64:
-> 2028     result = grib_get_double_array(msgid, key)
   2029 elif ktype is np.float32:
   2030     result = grib_get_float_array(msgid, key)

File ~\miniconda3\envs\wxdata\Lib\site-packages\gribapi\gribapi.py:1196, in grib_get_double_array(msgid, key)
   1194 vals_p = ffi.cast("double *", arr.ctypes.data)
   1195 err = lib.grib_get_double_array(h, key.encode(ENC), vals_p, length_p)
-> 1196 GRIB_CHECK(err)
   1197 return arr

File ~\miniconda3\envs\wxdata\Lib\site-packages\gribapi\gribapi.py:226, in GRIB_CHECK(errid)
    218 """
    219 Utility function checking the ecCodes error code and raising
    220 an error if that was set.
   (...)    223 @exception CodesInternalError
    224 """
    225 if errid:
--> 226     errors.raise_grib_error(errid)

File ~\miniconda3\envs\wxdata\Lib\site-packages\gribapi\errors.py:381, in raise_grib_error(errid)
    377 def raise_grib_error(errid):
    378     """
    379     Raise the GribInternalError corresponding to ``errid``.
    380     """
--> 381     raise ERROR_MAP[errid](errid)

FunctionalityNotEnabledError: Functionality not enabled

Accompanying data

https://dd.weather.gc.ca/20250918/WXO-DD/model_gem_global/15km/grib2/lat_lon/00/000/

Organisation

No response

edrewitz avatar Sep 18 '25 15:09 edrewitz

Hi @edrewitz, I downloaded a sample of this data and noticed that it is jpeg-encoded. Are you able to tell me how the ecCodes binary has been installed? You can inspect this by setting the following command-line environment variable before starting your Python program:

set ECCODES_PYTHON_TRACE_LIB_SEARCH=1

You should now get some output that tells you where the binary library is being found. That will help determine the cause - most likely that your version of the library has been built without jpeg support.

iainrussell avatar Sep 21 '25 15:09 iainrussell

Hi @iainrussell and thank you for your reply. The version of ecCodes I am using is 2.43.0. Is there a newer version I should install for jpeg support? Also, I am using a Windows OS.

edrewitz avatar Sep 21 '25 18:09 edrewitz

Hi @edrewitz, what I need to know is how you installed the ecCodes binary - this is separate from the ecCodes Python bindings. Perhaps you are running in a conda environment, or a pure 'pip' environment - these will have different builds of the ecCodes binary library. The environment variable I suggested above will also help us know where the binaries are coming from.

iainrussell avatar Sep 22 '25 09:09 iainrussell

Hi @iainrussell I installed cfgrib and thus ecCodes via pip.

edrewitz avatar Sep 23 '25 03:09 edrewitz

Hi @iainrussell I am curious if there are any plans in making the version on pip have the functionality the conda version has?

edrewitz avatar Sep 25 '25 15:09 edrewitz