Field¶
A Field represents a single horizontal slice of a
geophysical quantity at a particular time and vertical level. It is the fundamental data
structure in earthkit-data and bundles together:
the data values — a 2-D (or 1-D unstructured) array of floating-point numbers;
a set of format independent metadata components that fully describe the field (see below). This metadata is often referred to as the “high-level” metadata in the earthkit documentation.
raw metadata (e.g. ecCodes GRIB keys) from the original data source, when available.
Fields are created automatically when reading data through
from_source() and are normally accessed as members of a
FieldList. Refer to the
FieldList concept page for a full description of how to
select, iterate over, and manipulate collections of fields.
High-level metadata¶
The Field class is not polymorphic. Instead it is composed of a set of replaceable, polymorphic components, each responsible for a distinct aspect of the metadata.
List of high-level metadata keys
See the list of all available component metadata keys in Metadata key reference.
The following table lists the components that make up a field and the corresponding
classes that implement them. Use the Reference column to jump to the component’s dedicated page for a full description of its keys.
Attribute |
What it describes |
Reference |
Component class |
|---|---|---|---|
|
Physical quantity: variable name, units, CF names, chemical or optical properties. |
||
|
Temporal coordinate: base datetime, forecast step, valid datetime. |
||
|
Vertical coordinate: level value, level type, layer bounds. |
||
|
Horizontal grid: lat/lon arrays, bounding box, projection, grid type. |
||
|
Ensemble member identifier. |
||
|
Post-processing operations applied to produce the field (e.g. accumulation). |
||
|
User-defined key-value pairs; keys are arbitrary strings chosen by the caller. |
Each component exposes its metadata through named methods (e.g.
field.vertical.level()) and through the generic
get() method using a "component.key" prefix:
>>> import earthkit.data as ekd
>>> field = ekd.from_source("sample", "test.grib").to_fieldlist()[0]
>>> field.parameter.variable()
'2t'
>>> field.get("parameter.variable")
'2t'
>>> field.vertical.level()
0
>>> field.get("time.base_datetime")
datetime.datetime(2020, 1, 1, 0, 0)
The metadata keys can be used in sel() and order_by() to select and sort fields.
Raw metadata¶
The term “raw metadata” refers to the metadata available in the data object the field was created from. Currently, it is only available when the field is created from a GRIB message. The raw metadata can be accessed through the get() method using the "metadata.<key>" prefix. For example, we can access the ecCodes GRIB "shortName" key using:
>>> field.get("metadata.shortName")
'2t'
Alternatively, the metadata() method can also be used to access the raw metadata with or without a prefix. Actually, this method can only be used to access raw metadata. For example, we can access the ecCodes GRIB "shortName" key using:
>>> field.metadata("shortName")
'2t'
>>> field.metadata("metadata.shortName")
'2t'
There is a major difference between the two methods: the metadata() method will raise a KeyError if the key is not found, while the get() method allows to specify a default value to return if the key is not found. For example, if the field does not have raw (GRIB) metadata:
>>> field.get("metadata.shortName")
None
>>> field.get("metadata.shortName", default="N/A")
'N/A'
>>> field.metadata("shortName")
Traceback (most recent call last):
...
KeyError: 'shortName'
The raw metadata, when available, can also be used in methods such as sel() and order_by() by using the "metadata.<key>" prefix. For example, to select all fields with an ecCodes GRIB short name of "2t":
>>> fl = ekd.from_source("sample", "test.grib").to_fieldlist()
>>> fl_sel = fl.sel({"metadata.shortName": "2t"})
>>> len(fl_sel)
1
>>> fl_sel[0].get("metadata.shortName")
'2t'
Immutability of field values¶
Field values are immutable: values() always returns
a copy of the underlying array. Modifications to that copy do not affect the stored
data. This guarantees that the original data remains consistent no matter how many
downstream operations consume it.
Modifying a field¶
Because both values and metadata are immutable, changes are expressed by creating a
new field via set(). The method accepts a dictionary
of "component.key": value pairs (and/or a "values" entry) and returns a new field
with the requested changes applied while leaving all other attributes unchanged:
>>> new_field = field.set({"vertical.level": 500, "time.step": 6})
>>> new_field.vertical.level()
500
>>> new_field.time.step()
datetime.timedelta(seconds=21600)
Arithmetic operations¶
Fields support element-wise arithmetic directly (+, -, *, /). Each
operation returns a new field whose data is the result of the operation. The metadata
(parameter, time, vertical, geography, ensemble, proc) of the left-hand operand is
retained in the result without modification:
>>> fl = ekd.from_source("sample", "tuv_pl.grib").to_fieldlist()
>>> result = fl[0] + fl[1]
>>> result.parameter.variable() == fl[0].parameter.variable()
True