Mengapa GRIB Penting di Meteorologi Operasional
Kalau kamu sudah terbiasa kerja dengan ERA5 dalam format NetCDF, file GRIB terasa sedikit asing. Tapi hampir semua model NWP operasional — IFS dari ECMWF, GFS dari NCEP, bahkan output WRF yang sudah diproses — menyimpan datanya dalam format GRIB. Artinya, begitu kamu mulai bekerja dengan forecast nyata (bukan hanya reanalysis), GRIB adalah hal pertama yang akan kamu temui.
GRIB bukan format propietary yang bisa diabaikan — ini adalah standar resmi WMO (World Meteorological Organisation) untuk archiving dan pertukaran gridded data. Namanya singkatan dari General Regularly distributed Information in Binary form. WMO mendefinisikan format ini agar semua lembaga cuaca di dunia bisa saling bertukar output model tanpa bergantung pada satu vendor tertentu.
Tutorial ini mengajak kita dari awal: instalasi tooling, download sample file GRIB2 dari ECMWF Open Data, membukanya dengan xarray, lalu memvisualisasikannya sebagai peta suhu di atas Indonesia. Tidak ada konversi ke NetCDF dulu — kita baca GRIB langsung.
Format dan Struktur Dasar GRIB
Sebuah file GRIB adalah deretan messages yang disusun berurutan secara binary. Setiap message membawa tepat satu parameter, satu level, dan satu timestep — beserta seluruh metadata-nya. Tidak ada header global seperti di NetCDF; setiap message adalah unit yang mandiri dan self-describing.
Ada dua edisi yang perlu dipahami: GRIB1 dan GRIB2. GRIB1 diperkenalkan tahun 1990 dan terdiri dari 6 sections per message. Ia punya batasan keras: maksimal 127 level vertikal dan hanya 128 parameter yang bisa didefinisikan. WMO resmi menghapus GRIB1 dari Manual on Codes pada 2016, jadi secara standar ia sudah deprecated.
GRIB2 hadir tahun 2001 dengan desain yang jauh lebih fleksibel: 9 sections per message, di mana tiga di antaranya (Section 3 Grid Definition, Section 4 Product Definition, Section 5 Data Representation) berbasis template. Template-based design ini membuat GRIB2 bisa mengakomodasi jutaan parameter, level tak terbatas, dan compression method modern seperti CCSDS. ECMWF mulai memproduksi data operasional dalam campuran GRIB1 dan GRIB2 sejak IFS Cycle 37r2 pada Mei 2011 — tepat ketika model bergerak ke 137 level vertikal, melebihi batas 127-level GRIB1.
Sumber: ECMWF Confluence Wiki (link)
Satu hal yang sering mempersulit pembacaan GRIB2 di Python: longitude-nya menggunakan rentang 0–360°, bukan −180 hingga 180°. Ini konsekuensi dari penggunaan micro-degrees precision di GRIB2. Kita perlu perhatikan ini saat melakukan seleksi bbox.
Instalasi ecCodes dan cfgrib
Tool utama untuk membaca GRIB dari Python adalah cfgrib — library dari ECMWF yang memetakan GRIB messages ke xarray Datasets mengikuti CF Conventions. Di baliknya, cfgrib mengandalkan ecCodes, library C dari ECMWF yang menangani low-level decoding. Cara termudah menggunakan cfgrib adalah sebagai xarray engine: xr.open_dataset('file.grib2', engine='cfgrib').
Untuk conda, conda install -c conda-forge cfgrib menangani dependency binary ecCodes secara otomatis. Untuk pip, sejak ecCodes Python bindings 2.37.0 (September 2024), binary ecCodes sudah di-bundle bersama pip package — jadi pip install cfgrib seharusnya langsung berfungsi. Kita verifikasi dengan python -m cfgrib selfcheck.
pip install cfgrib ecmwf-opendata -q
python -m cfgrib selfcheck
Found: ecCodes v2.46.2.
Your system is ready.
Output selfcheck yang sukses akan menampilkan baris seperti Found: ecCodes ... beserta versi library-nya. Kalau ada baris ERROR di sini, periksa apakah ecCodes binary sudah terinstall — pada beberapa sistem Linux, kamu perlu apt install libeccodes-dev terlebih dahulu sebelum pip install.
Mengunduh Sample GRIB dari ECMWF Open Data
ECMWF menyediakan forecast real-time secara gratis melalui ECMWF Open Data — data IFS dan AIFS dalam format GRIB2 resolusi 0,25° di bawah lisensi CC-BY-4.0. Tidak perlu akun ECMWF, tidak perlu API key. Rolling archive-nya menyimpan sekitar 12 forecast run terakhir (sekitar 2–3 hari ke belakang).
Satu catatan penting: sejak Juli 2023, file ECMWF Open Data menggunakan CCSDS compression di dalam GRIB2. Ini membutuhkan ecCodes ≥ 2.25.0 untuk bisa di-decode. Conda-forge secara default sudah memenuhi syarat ini.
Kita download forecast 2m temperature (parameter 2t) pada step +24 jam menggunakan package ecmwf-opendata. Snippet di bawah menggunakan guard if not os.path.exists sehingga file hanya didownload sekali — jalankan lagi kapanpun tanpa takut duplikasi.
import os
from ecmwf.opendata import Client
OUT = "ecmwf_2t_step24.grib2"
if not os.path.exists(OUT):
client = Client(source="ecmwf")
client.retrieve(
step=24,
type="fc",
param="2t",
target=OUT,
)
size_mb = os.path.getsize(OUT) / 1e6
print(f"File: {OUT}")
print(f"Size: {size_mb:.2f} MB")
print("Download selesai.")
By downloading data from the ECMWF open data dataset, you agree to the terms: Attribution 4.0 International (CC BY 4.0). Please attribute ECMWF when downloading this data.
File: ecmwf_2t_step24.grib2
Size: 0.66 MB
Download selesai.
File yang diunduh biasanya berukuran 1–5 MB untuk satu parameter pada resolusi 0,25°. Data tersedia dari empat sumber (ECMWF, AWS, Azure, Google Cloud) melalui interface Python yang sama, sehingga download tetap stabil meski satu sumber sedang down.
Membuka dan Memeriksa Dataset GRIB dengan xarray
Ini bagian inti tutorial. Membuka file GRIB dengan xarray sesederhana memanggil xr.open_dataset dan menyebutkan engine='cfgrib'. Namun ada satu hal yang perlu dipahami terlebih dahulu.
Kebanyakan file GRIB2 nyata — termasuk output IFS dan GFS lengkap — berisi messages dengan metadata yang tidak kompatibel satu sama lain: typeOfLevel berbeda (surface, isobaricInhPa, heightAboveGround), stepType berbeda (instant, accum), dan sebagainya. Kumpulan messages yang tidak homogen ini tidak bisa membentuk satu xarray Dataset yang konsisten — cfgrib akan error atau mengeluh soal multiple hypercubes.
Solusinya ada dua. Pertama, gunakan filter_by_keys di backend_kwargs untuk memilih subset yang homogen. Kedua, gunakan cfgrib.open_datasets() (perhatikan s di akhir) yang secara otomatis mendeteksi semua hypercube yang valid dan mengembalikannya sebagai list of Datasets. Untuk file single-parameter seperti yang kita download, biasanya satu call sudah cukup — tapi kita tambahkan filter untuk kelengkapan.
import xarray as xr
ds = xr.open_dataset(
"ecmwf_2t_step24.grib2",
engine="cfgrib",
backend_kwargs={
"indexpath": "",
"filter_by_keys": {"typeOfLevel": "heightAboveGround"},
},
)
print(ds)
print()
print("Variable t2m:")
print(ds["t2m"])
<xarray.Dataset> Size: 4MB
Dimensions: (latitude: 721, longitude: 1440)
Coordinates:
* latitude (latitude) float64 6kB 90.0 89.75 89.5 ... -89.75 -90.0
* longitude (longitude) float64 12kB -180.0 -179.8 ... 179.5 179.8
time datetime64[ns] 8B ...
step timedelta64[ns] 8B ...
heightAboveGround float64 8B ...
valid_time datetime64[ns] 8B ...
Data variables:
t2m (latitude, longitude) float32 4MB ...
Attributes:
GRIB_edition: 2
GRIB_centre: ecmf
GRIB_centreDescription: European Centre for Medium-Range Weather Forecasts
GRIB_subCentre: 0
Conventions: CF-1.7
institution: European Centre for Medium-Range Weather Forecasts
history: 2026-05-26T00:12 GRIB to CDM+CF via cfgrib-0.9.1...
Variable t2m:
<xarray.DataArray 't2m' (latitude: 721, longitude: 1440)> Size: 4MB
[1038240 values with dtype=float32]
Coordinates:
* latitude (latitude) float64 6kB 90.0 89.75 89.5 ... -89.75 -90.0
* longitude (longitude) float64 12kB -180.0 -179.8 ... 179.5 179.8
time datetime64[ns] 8B ...
step timedelta64[ns] 8B ...
heightAboveGround float64 8B ...
valid_time datetime64[ns] 8B ...
Attributes: (12/30)
GRIB_paramId: 167
GRIB_dataType: fc
GRIB_numberOfPoints: 1038240
GRIB_typeOfLevel: heightAboveGround
GRIB_stepUnits: 1
GRIB_stepType: instant
... ...
GRIB_name: 2 metre temperature
GRIB_shortName: 2t
GRIB_units: K
long_name: 2 metre temperature
units: K
standard_name: air_temperature
Output di atas menampilkan dimensi dataset (latitude, longitude), koordinat (valid_time, step, heightAboveGround), dan variabel t2m dalam satuan Kelvin. Kamu juga akan melihat file index .grib2.XXXXXX.idx terbuat di direktori yang sama — ini normal dan mempercepat pembacaan berikutnya. Bukan sampah, jangan dihapus.
Ekstraksi dan Visualisasi Forecast 2m Temperature
Dengan dataset terbuka, kita bisa langsung seleksi area Indonesia. Ingat bahwa koordinat longitude di GRIB2 bertanda 0–360°, bukan −180 hingga 180°. Jadi 95°E tetap 95, 141°E tetap 141 — kita aman. Untuk latitudes, tanda negatif untuk selatan tetap berlaku.
import numpy as np
# Seleksi bbox Indonesia: lat -11 s/d 6, lon 95 s/d 141 (0-360)
indonesia = ds["t2m"].sel(
latitude=slice(6, -11),
longitude=slice(95, 141),
)
# Konversi dari Kelvin ke Celsius
indonesia_c = indonesia - 273.15
print("Dimensi:", indonesia_c.dims)
print("Shape:", indonesia_c.shape)
print(f"Valid time: {ds.valid_time.values}")
print()
print(f"Suhu 2m (°C) — Indonesia:")
print(f" Min : {float(indonesia_c.min()):.2f} °C")
print(f" Max : {float(indonesia_c.max()):.2f} °C")
print(f" Mean: {float(indonesia_c.mean()):.2f} °C")
Dimensi: ('latitude', 'longitude')
Shape: (69, 185)
Valid time: 2026-05-26T12:00:00.000000000
Suhu 2m (°C) — Indonesia:
Min : 5.77 °C
Max : 31.11 °C
Mean: 27.29 °C
Angka-angka di atas adalah forecast suhu 2 meter di atas permukaan untuk seluruh Indonesia pada +24 jam. valid_time menunjukkan kapan forecast ini berlaku — bukan waktu run model. Rentang suhu yang wajar untuk Indonesia biasanya 20–35 °C, dengan nilai lebih rendah di pegunungan Papua dan Sulawesi.
Sekarang kita visualisasikan field-nya sebagai peta menggunakan cartopy.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np
# Ambil data Indonesia dalam Celsius
t2m_c = (ds["t2m"].sel(
latitude=slice(6, -11),
longitude=slice(95, 141),
) - 273.15)
lons = t2m_c.longitude.values
lats = t2m_c.latitude.values
data = t2m_c.values
valid_time = str(ds.valid_time.values)[:16]
fig, ax = plt.subplots(
figsize=(12, 7),
subplot_kw={"projection": ccrs.PlateCarree()},
)
cf = ax.contourf(
lons, lats, data,
levels=np.arange(16, 38, 1),
cmap="RdYlBu_r",
transform=ccrs.PlateCarree(),
extend="both",
)
ax.add_feature(cfeature.COASTLINE, linewidth=0.8)
ax.add_feature(cfeature.BORDERS, linewidth=0.5, linestyle="--")
ax.add_feature(cfeature.LAND, facecolor="none", edgecolor="gray", linewidth=0.3)
gl = ax.gridlines(draw_labels=True, linewidth=0.4, color="gray", alpha=0.6)
gl.top_labels = False
gl.right_labels = False
gl.xlocator = mticker.FixedLocator([95, 105, 115, 125, 135, 141])
gl.ylocator = mticker.FixedLocator([-10, -5, 0, 5])
cbar = plt.colorbar(cf, ax=ax, orientation="horizontal", pad=0.05, shrink=0.8)
cbar.set_label("Suhu 2m (°C)", fontsize=11)
ax.set_extent([95, 141, -11, 6], crs=ccrs.PlateCarree())
ax.set_title(
f"Forecast Suhu 2m ECMWF IFS — +24 jam\nValid: {valid_time} UTC",
fontsize=13,
pad=10,
)
plt.tight_layout()
plt.savefig("/work/snippet-5-1.png", dpi=120, bbox_inches="tight")
plt.show()
Peta di atas memperlihatkan distribusi spasial suhu 2m dari forecast IFS pada +24 jam. Area biru (lebih dingin) umumnya berkorespondensi dengan pegunungan dan dataran tinggi, sementara area merah-kuning (lebih hangat) muncul di pesisir pantai dan permukaan laut. Gradien yang tajam di perairan sekitar Sulawesi dan Maluku adalah ciri khas SST yang hangat di wilayah maritim Indonesia.
Gotchas dan Langkah Berikutnya
Beberapa hal yang perlu diingat saat bekerja dengan GRIB di Python:
Index files. Saat pertama kali membuka file GRIB, cfgrib membuat file index dengan nama seperti ecmwf_2t_step24.grib2.923d8.idx. Ini normal — index mempercepat pembacaan berikutnya. Jangan dihapus, dan jangan di-commit ke git kalau tidak sengaja.
Multiple hypercubes. Saat kamu download file GRIB "lengkap" dari GFS atau ECMWF yang berisi banyak parameter, hampir pasti kamu butuh filter_by_keys. Kalau tidak yakin apa yang ada di dalam file, gunakan cfgrib.open_datasets('file.grib2') — ia mengembalikan list semua hypercube yang terdeteksi, lalu kamu bisa inspect satu-satu.
stepType untuk presipitasi. Field seperti total precipitation di GFS menggunakan stepType='accum' (akumulasi), bukan 'instant'. Tanpa filter yang tepat, kamu bisa mendapat error atau hasil yang salah. Selalu cek ds.attrs dan metadata GRIB sebelum interpret angka.
CCSDS compression. File ECMWF Open Data sejak Juli 2023 menggunakan CCSDS compression. Pastikan ecCodes yang terinstall versinya ≥ 2.25.0. Conda-forge secara default sudah memenuhi syarat ini; kalau pakai pip, update secara berkala.
Langkah selanjutnya yang bisa dicoba: download parameter lain seperti total precipitation (tp) atau wind component (10u, 10v) dari ECMWF Open Data, lalu aplikasikan teknik yang sama. Untuk GFS, NOMADS menyediakan file GRIB2 yang bisa diakses via URL langsung — strukturnya lebih kompleks karena satu file bisa berisi ratusan parameter, tapi pendekatan filter_by_keys dan cfgrib.open_datasets() tetap berlaku.
Eksplorasi artikel meteorologi lainnya di meteo.my.id — kunjungi https://meteo.my.id untuk arsip lengkap, mulai dari analisis ERA5 dan xarray hingga pemodelan atmosfer dengan Python.
Referensi
- What are GRIB files and how can I read them — ECMWF Confluence — Definisi GRIB, perbedaan GRIB1 vs GRIB2, dan ecCodes sebagai tool utama pembacaan dari Python.
- About GRIB data format — ECMWF Confluence Wiki — Sejarah edisi GRIB (0, 1, 2), struktur sections, dan template-based design GRIB2.
- Migration from GRIB1 to GRIB2 — ECMWF Newsletter 175 — Program migrasi ECMWF dari GRIB1 ke GRIB2, batasan GRIB1, dan roadmap IFS Cycle 51r1.
- ecmwf/cfgrib — GitHub — Dokumentasi cfgrib: instalasi, xarray engine, filter_by_keys, dan cfgrib.open_datasets().
- Open data — ECMWF — Portal ECMWF Open Data: forecast IFS dan AIFS gratis dalam GRIB2 resolusi 0,25° lewat Python client ecmwf-opendata.
Tidak ada komentar:
Posting Komentar