GRIB: using the metadata object
In this notebook we will work with a GRIB file containing 6 messages. First we ensure the example file is available, then read the file with from_source().
[1]:
import earthkit.data as ekd
ekd.download_example_file("test6.grib")
ds = ekd.from_source("file", "test6.grib")
The metadata object
The recommended way to get field metadata for a given key or keys is to use metadata(). See GRIB: inspecting contents for more examples.
[2]:
ds[0].metadata("shortName")
[2]:
't'
Internally the field metadata is represented by a GribFieldMetadata object. Calling metadata() without any arguments will return this object.
[3]:
md = ds[0].metadata()
md
[3]:
<earthkit.data.readers.grib.metadata.GribFieldMetadata at 0x2a919e170>
It can be used as a dict.
[4]:
md["shortName"], md.get("level")
[4]:
('t', 1000)
Warning: this object does not own a GRIB handle but contains a reference to the field, which provides access to the GRIB handle. Therefore if you need to store it for later use it is recommended to create a copy with override() (see below) to decouple it from the field object.
Creating a copy of the metadata object
We can create a copy with override(), which always returns a new metadata object storing a cloned GRIB handle, thus it is decoupled from the field.
[5]:
md_copy = md.override()
By default override() is called with the headers_only_clone=True option to clone a new GRIB handle with all the data values (and some related information) removed. With this the resulting object can be significantly smaller, especially if the data section is large. The downside is that now the value related keys either cannot be accessed or give back wrong values. E.g when using the “average” key we get:
[6]:
md["average"], md_copy["average"]
[6]:
(279.70703560965404, 47485.4296875)
To get a copy without shrinking the GRIB handle use headers_only_clone=False.
[7]:
md_copy_full = md.override(headers_only_clone=False)
[8]:
md_copy_full["average"]
[8]:
279.70703560965404
Changing the metadata
To change metadata values pass key value pairs or a dict to override().
[9]:
md_mod = md.override(shortName="z", level="850")
md_mod["shortName"], md_mod["level"]
[9]:
('z', 850)
Since md_mod contains a clone of the GRIB handle the original metadata did not change.
[10]:
md["shortName"], md["level"]
[10]:
('t', 1000)
Creating array fields from metadata and values
GRIB metadata objects play a part in building new fieldlists from (altered) values and metadata.
The following example computes the wind speed on 1000 hPa and creates a new fieldlist with a single field containing the new values. The metadata is taken from the u field and the shortName is modified.
[11]:
from earthkit.data import FieldList
import numpy as np
u = ds.sel(param="u", level=1000)[0]
v = ds.sel(param="v", level=1000)[0]
speed = np.sqrt(u.values**2 + v.values**2)
md_speed = u.metadata().override(shortName="ws")
ds_speed = FieldList.from_array(speed, md_speed)
[12]:
ds_speed.ls()
[12]:
| centre | shortName | typeOfLevel | level | dataDate | dataTime | stepRange | dataType | number | gridType | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | ecmf | ws | isobaricInhPa | 1000 | 20180801 | 1200 | 0 | an | 0 | regular_ll |
The resulting fieldlist contains an ArrayField, which is composed of a numpy array storing the values and a metadata object owning its own GRIB handle with a trimmed down data section. Since the values array is decoupled from the GRIB handle stored in the metadata object, accessing metadata keys related to the data values is forbidden. Getting metadata on these keys will throw an exception.
[13]:
ds_speed[0].metadata()
[13]:
<earthkit.data.readers.grib.metadata.RestrictedGribMetadata at 0x2a9229180>
[14]:
ds_speed[0].metadata("name")
[14]:
'Wind speed'
[15]:
try:
ds_speed[0].metadata("average")
except KeyError as e:
print(f"KeyError {e}")
KeyError 'average'
However, strictly speaking these keys do not represent metadata and they can be easily computed from the field values when needed.
[16]:
ds_speed[0].values.mean()
[16]:
7.450183054360252
[ ]: