GRIB: create fieldlist from array and metadata

In this notebook we will show how to do some computations with GRIB data and generate a array fieldlist from the results.

First we read some GRIB data containing pressure level fields.

[1]:
import earthkit.data as ekd
from earthkit.data import FieldList
import numpy as np

ekd.download_example_file("tuv_pl.grib")
ds = ekd.from_source("file", "tuv_pl.grib")

We will use the following method to compute the potential temperature:

[2]:
def potential_temperature(t, p):
    # t: temperature in K
    # p: pressure in Pa
    return t*(100000./p)**0.285611

Working with a single field

In this example we compute the potential temperature for the 850 hPa level using the 4th field from the fieldlist.

[3]:
f = ds[3]
f, f.metadata("units")
[3]:
(GribField(t,850,20180801,1200,0,0), 'K')

The computations are done with numpy arrays:

[4]:
t = f.values
print("typeOfLevel=", f.metadata("typeOfLevel"))
p = f.metadata("level")*100. #hPa -> Pa
t_new = potential_temperature(t, p)
t_new[:10]
typeOfLevel= isobaricInhPa
[4]:
array([285.48786915, 285.48786915, 285.48786915, 285.48786915,
       285.48786915, 285.48786915, 285.48786915, 285.48786915,
       285.48786915, 285.48786915])

We create a new GribMetadata object from the source field’s metadata() using override(). The original metadata remains the same.

[5]:
md_new = f.metadata().override(shortName="pt")
print(md_new["shortName"])
print(f.metadata("shortName"))
pt
t

A new FieldList (type of SimpleFieldList) can be created from the resulting ndarray and the modified metadata. It will store a list of ArrayField fields each containing a values array and a metadata object entirely in memory. This fieldlist behaves as if it were a GribFieldList.

[6]:
ds_new = FieldList.from_array(t_new, md_new)
ds_new.ls()
[6]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType
0 ecmf pt isobaricInhPa 850 20180801 1200 0 an 0 regular_ll
[7]:
ds_new[0]
[7]:
ArrayField(pt,850,20180801,1200,0,0)

The new fieldlist can be saved into a GRIB file:

[8]:
path = "_pt_single.grib"
ds_new.to_target("file", path)

# read file back and check content
ds1 = ekd.from_source("file",path)
ds1.ls()
[8]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType
0 ecmf pt isobaricInhPa 850 20180801 1200 0 an 0 regular_ll

Working with multiple fields

In this example we compute the potential temperature for 3 pressure levels.

[9]:
fs = ds.sel(shortName="t", level=[850, 700, 500])
fs.ls(extra_keys=["units"])
[9]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType units
0 ecmf t isobaricInhPa 850 20180801 1200 0 an 0 regular_ll K
1 ecmf t isobaricInhPa 700 20180801 1200 0 an 0 regular_ll K
2 ecmf t isobaricInhPa 500 20180801 1200 0 an 0 regular_ll K
[10]:
p = np.asarray(fs.metadata("level")).reshape(-1, 1)*100. # hPa -> Pa
t_new = potential_temperature(fs.values, p)
t_new.shape
[10]:
(3, 84)

We create an array fieldlist from the resulting ndarray and the modified metadata.

[11]:
md_new = [f.metadata().override(shortName="pt") for f in fs]
ds_new = FieldList.from_array(t_new, md_new)
ds_new.ls()
[11]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType
0 ecmf pt isobaricInhPa 850 20180801 1200 0 an 0 regular_ll
1 ecmf pt isobaricInhPa 700 20180801 1200 0 an 0 regular_ll
2 ecmf pt isobaricInhPa 500 20180801 1200 0 an 0 regular_ll

The new fieldlist can be saved into a GRIB file:

[12]:
path = "_pt_multi.grib"
ds_new.to_target("file", path)

# read file back and check content
ds1 = ekd.from_source("file", path)
ds1.ls()
[12]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType
0 ecmf pt isobaricInhPa 850 20180801 1200 0 an 0 regular_ll
1 ecmf pt isobaricInhPa 700 20180801 1200 0 an 0 regular_ll
2 ecmf pt isobaricInhPa 500 20180801 1200 0 an 0 regular_ll

Performing the computations in a loop

In this example we create an empty FieldList and add the results of the computations to it in a loop.

[13]:
fs = ds.sel(shortName="t", level=[850, 700, 500])

# create an empty fieldlist
ds_r = FieldList()

for f in fs:
    p = f.metadata("level")*100. # hPa -> Pa
    t_new = potential_temperature(f.values, p)
    md_new = f.metadata().override(shortName="pt")

    # create new numpy fieldlist with a single field
    ds_new = FieldList.from_array(t_new, md_new)

    # add it to the resulting fieldlist
    ds_r += ds_new
[14]:
ds_r.ls()
[14]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType
0 ecmf pt isobaricInhPa 850 20180801 1200 0 an 0 regular_ll
1 ecmf pt isobaricInhPa 700 20180801 1200 0 an 0 regular_ll
2 ecmf pt isobaricInhPa 500 20180801 1200 0 an 0 regular_ll

The new fieldlist can be saved into a GRIB file:

[15]:
path = "_pt_from_loop.grib"
ds_r.to_target("file", path)

# read file back and check content
ds1 = ekd.from_source("file", path)
ds1.ls()
[15]:
centre shortName typeOfLevel level dataDate dataTime stepRange dataType number gridType
0 ecmf pt isobaricInhPa 850 20180801 1200 0 an 0 regular_ll
1 ecmf pt isobaricInhPa 700 20180801 1200 0 an 0 regular_ll
2 ecmf pt isobaricInhPa 500 20180801 1200 0 an 0 regular_ll
[ ]: