TANGERANG SELATAN WEATHER

Senin, 15 Juni 2026

Menganalisis Shear Angin dengan Model GFS

Annual mean 500 to 850 hPa wind shear magnitude over Indonesia from ERA5 2024 data

Shear angin vertikal adalah salah satu faktor lingkungan paling penting dalam prakiraan intensitas siklon tropis (TC). Seorang forecaster yang memantau perkembangan TC di Samudra Pasifik barat atau Samudra Hindia selatan selalu memeriksa berapa besar wind shear di sekitar sistem sebelum memproyeksikan apakah badai akan menguat atau melemah. Tutorial ini mengajarkan cara menghitung wind shear 500–850 hPa dari data ERA5 menggunakan Python dan xarray, memetakannya dengan cartopy, lalu mengklasifikasikannya ke dalam rezim operasional. Di bagian akhir kita juga membahas cara mengakses data GFS real-time dari NOMADS untuk analisis serupa.

Pengenalan Shear Angin dan Peran GFS

Wind shear vertikal, atau dalam bahasa operasional sering disebut cukup "shear", adalah perbedaan vektor angin horizontal antara dua level tekanan berbeda. American Meteorological Society (AMS) mendefinisikannya sebagai variasi (biasanya turunan arah) dari medan vektor angin sepanjang suatu arah di ruang. Dalam konteks prakiraan TC, shear konvensional dihitung sebagai selisih vektor antara angin di 200 hPa (troposfer atas) dan 850 hPa (troposfer bawah) — disebut deep-layer shear (DLS).

Secara operasional, GFS menjadi model utama yang dipakai untuk mengevaluasi shear karena tersedia real-time empat kali sehari (siklus 00, 06, 12, 18 UTC), resolusi 0,25°, dan dapat diakses langsung dari NOMADS NCEP tanpa registrasi. Output GFS digunakan oleh Climate Prediction Center (CPC) NOAA untuk memproduksi peta 200–850 hPa shear 10-hari yang menjadi referensi standar bagi para forecaster TC di seluruh dunia.

Relevansinya untuk Indonesia sangat konkret. Kawasan maritim kontinen Indonesia berada di persimpangan dua basin TC aktif — Samudra Pasifik barat dan Samudra Hindia selatan. Pemantauan shear di wilayah ini membantu forecaster menilai potensi pembentukan TC dan mengevaluasi risiko penerbangan (low-level wind shear, LLWS) di bandara-bandara pesisir.

Konsep Shear Angin Vertikal

Secara formal, deep-layer shear didefinisikan sebagai:

$$\vec{S} = \vec{V}_{200} - \vec{V}_{850}$$

dan magnitudonya:

$$|\vec{S}| = \sqrt{(\Delta u)^2 + (\Delta v)^2}$$

di mana \(\Delta u = u_{200} - u_{850}\) dan \(\Delta v = v_{200} - v_{850}\).

Tanda hasilnya tidak berubah apabila urutan pengurangan dibalik (850 − 200) karena kita mengambil magnitude. Yang penting adalah konsistensi — gunakan selalu \(\vec{V}_{\text{atas}} - \vec{V}_{\text{bawah}}\).

Threshold operasional yang dipakai secara luas adalah:

  • < 8 m/s: favorable untuk perkembangan TC — ini adalah threshold yang dipakai CPC dalam produk shear 10-harinya
  • < 10 m/s (~20 kt): soft limit yang digunakan model SHIPS (Statistical Hurricane Intensity Prediction System) dari AOML/NOAA; probabilitas rapid intensification (RI) paling tinggi di bawah nilai ini
  • > 10 m/s: inhibitory — shear mulai "merobekkan" vortex TC secara vertikal, mengganggu simetri eyewall, dan membawa udara kering ke dalam core badai

Untuk kepentingan tutorial ini, kita akan menghitung 500–850 hPa shear (low-to-mid-layer) menggunakan data ERA5 2024. Ini bukan DLS standar (yang butuh 200 hPa), melainkan representasi yang valid untuk menganalisis angin jet tingkat rendah dan interaksi monsun–TC di kawasan Indonesia. Matematika vektornya persis sama.

Diagram diagram-1

Skema kalkulasi wind shear vertikal dan klasifikasi rezim operasional berdasarkan threshold CPC dan SHIPS/AOML.

Mengunduh Data Tekanan Level dari ERA5

Data yang kita butuhkan adalah komponen u-wind dan v-wind di level tekanan 500 dan 850 hPa untuk domain Indonesia. Kita download dari CDS (Climate Data Store) Copernicus menggunakan cdsapi. Untuk mendaftar akun CDS dan mengonfigurasi .cdsapirc, kunjungi cds.climate.copernicus.eu.

Download dilakukan sekali saja — setelah file ada di direktori kerja, snippet berikutnya langsung membaca dari file lokal tanpa perlu koneksi lagi.

import os
import cdsapi
import xarray as xr

OUT_U = "era5_u_pl500-850_indonesia_2024_d.nc"
OUT_V = "era5_v_pl500-850_indonesia_2024_d.nc"

# Download u-wind jika belum ada
if not os.path.exists(OUT_U):
    c = cdsapi.Client(quiet=True)
    c.retrieve(
        "reanalysis-era5-pressure-levels",
        {
            "product_type": "reanalysis",
            "variable": ["u_component_of_wind"],
            "pressure_level": ["500", "850"],
            "year": "2024",
            "month": [f"{m:02d}" for m in range(1, 13)],
            "day":   [f"{d:02d}" for d in range(1, 32)],
            "time":  ["00:00"],
            "area":  [6, 95, -11, 141],
            "format": "netcdf",
        },
        OUT_U,
    )

# Download v-wind jika belum ada
if not os.path.exists(OUT_V):
    c = cdsapi.Client(quiet=True)
    c.retrieve(
        "reanalysis-era5-pressure-levels",
        {
            "product_type": "reanalysis",
            "variable": ["v_component_of_wind"],
            "pressure_level": ["500", "850"],
            "year": "2024",
            "month": [f"{m:02d}" for m in range(1, 13)],
            "day":   [f"{d:02d}" for d in range(1, 32)],
            "time":  ["00:00"],
            "area":  [6, 95, -11, 141],
            "format": "netcdf",
        },
        OUT_V,
    )

ds_u = xr.open_dataset(OUT_U)
ds_v = xr.open_dataset(OUT_V)

# Tangani nama dimensi waktu (valid_time atau time)
time_dim_u = "valid_time" if "valid_time" in ds_u.dims else "time"
time_dim_v = "valid_time" if "valid_time" in ds_v.dims else "time"

print("=== u-wind dataset ===")
print(f"Dims : {dict(ds_u.dims)}")
print(f"Vars : {list(ds_u.data_vars)}")
print(f"Levels: {ds_u['pressure_level'].values.tolist()} hPa")
print(f"Time range: {str(ds_u[time_dim_u].values[0])[:10]} — {str(ds_u[time_dim_u].values[-1])[:10]}")
print()
print("=== v-wind dataset ===")
print(f"Dims : {dict(ds_v.dims)}")
print(f"Vars : {list(ds_v.data_vars)}")
=== u-wind dataset ===
Dims : {'valid_time': 366, 'pressure_level': 2, 'latitude': 69, 'longitude': 185}
Vars : ['u']
Levels: [850.0, 500.0] hPa
Time range: 2024-01-01 — 2024-12-31

=== v-wind dataset ===
Dims : {'valid_time': 366, 'pressure_level': 2, 'latitude': 69, 'longitude': 185}
Vars : ['v']

Kedua file tersebut berisi data harian pukul 00 UTC sepanjang tahun 2024 untuk domain Indonesia (6°N–11°S, 95°E–141°E) pada dua level tekanan (500 dan 850 hPa). Ukuran file masing-masing sekitar 30–50 MB — cukup kecil untuk disimpan lokal dan dibaca berulang kali.

Menghitung Magnitude Shear Angin

Dengan dataset di tangan, kita ekstrak komponen angin di masing-masing level lalu hitung shear vektornya. Formula yang diimplementasikan:

$$|\vec{S}_{500\text{–}850}| = \sqrt{(u_{500} - u_{850})^2 + (v_{500} - v_{850})^2}$$

import numpy as np

# Tentukan nama dimensi waktu
time_dim = "valid_time" if "valid_time" in ds_u.dims else "time"

# Ekstrak komponen per level
u500 = ds_u["u"].sel(pressure_level=500)
u850 = ds_u["u"].sel(pressure_level=850)
v500 = ds_v["v"].sel(pressure_level=500)
v850 = ds_v["v"].sel(pressure_level=850)

# Pastikan koordinat waktu selaras
u500 = u500.assign_coords({time_dim: ds_v[time_dim]}) if time_dim in ds_v.coords else u500

# Hitung komponen shear dan magnitude
du = u500.values - u850.values
dv = v500.values - v850.values
shear_mag = np.sqrt(du**2 + dv**2)   # shape: (time, lat, lon)

# Statistik domain — mean dan max sepanjang 2024
domain_mean = float(np.nanmean(shear_mag))
domain_max  = float(np.nanmax(shear_mag))
print(f"Domain mean shear (500–850 hPa, 2024) : {domain_mean:.2f} m/s")
print(f"Domain max  shear (500–850 hPa, 2024) : {domain_max:.2f} m/s")
print()

# Monthly mean (rata-rata spasial per bulan)
time_vals = ds_u[time_dim].values
import pandas as pd
months = pd.DatetimeIndex(time_vals).month
print("Monthly domain-mean shear (m/s):")
print(f"{'Bulan':<8}", end="")
for m in range(1, 13):
    mask = months == m
    if mask.sum() > 0:
        val = float(np.nanmean(shear_mag[mask]))
        print(f"  {m:02d}: {val:.2f}", end="")
print()
print()
print("Threshold reference:")
print("  < 8 m/s  → favorable TC development (CPC operational threshold)")
print("  < 10 m/s → rapid intensification possible (SHIPS/AOML soft limit)")
print("  > 10 m/s → generally inhibitory for TC intensification")
Domain mean shear (500–850 hPa, 2024) : 6.18 m/s
Domain max  shear (500–850 hPa, 2024) : 36.73 m/s

Monthly domain-mean shear (m/s):
Bulan     01: 5.60  02: 5.81  03: 6.12  04: 5.06  05: 6.63  06: 6.27  07: 6.62  08: 6.73  09: 7.05  10: 5.74  11: 5.15  12: 7.27

Threshold reference:
  < 8 m/s  → favorable TC development (CPC operational threshold)
  < 10 m/s → rapid intensification possible (SHIPS/AOML soft limit)
  > 10 m/s → generally inhibitory for TC intensification

Angka domain mean dan max di atas menggambarkan kondisi rata-rata shear setingkat 500–850 hPa di wilayah Indonesia sepanjang 2024. Bandingkan nilai bulanan tersebut dengan threshold 8 dan 10 m/s untuk melihat bulan-bulan mana yang secara rata-rata masuk rezim favorable atau inhibitory.

Memetakan Distribusi Shear di Maritim Kontinen

Statistik angka saja tidak cukup — kita perlu melihat distribusi spasialnya. Plot berikut menampilkan annual-mean shear magnitude di domain Indonesia dengan colormap yang dicetak pada batas 8 dan 10 m/s agar pembaca bisa langsung membaca rezim TC per wilayah.

import os
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np

# Annual mean shear (rata-rata sepanjang sumbu waktu)
shear_annual_mean = np.nanmean(shear_mag, axis=0)   # shape: (lat, lon)

lat = ds_u["latitude"].values
lon = ds_u["longitude"].values

# Colormap bertingkat: hijau < 8, kuning 8–10, merah > 10 m/s
cmap = mcolors.LinearSegmentedColormap.from_list(
    "shear_regime",
    [
        (0.0,   "#2ecc71"),   # 0 m/s — hijau (favorable)
        (0.4,   "#a8e6a3"),   # ~8 m/s — transisi
        (0.5,   "#f39c12"),   # 10 m/s — marginal
        (0.65,  "#e67e22"),
        (1.0,   "#c0392b"),   # max — inhibitory
    ]
)
vmax = 25.0

fig, ax = plt.subplots(
    figsize=(12, 6),
    subplot_kw={"projection": ccrs.PlateCarree()}
)

pcm = ax.pcolormesh(
    lon, lat, shear_annual_mean,
    transform=ccrs.PlateCarree(),
    cmap=cmap,
    vmin=0, vmax=vmax,
    shading="auto",
)

ax.add_feature(cfeature.COASTLINE, linewidth=0.8, edgecolor="black")
ax.add_feature(cfeature.BORDERS,   linewidth=0.4, edgecolor="gray")
ax.add_feature(cfeature.LAND,      facecolor="none", edgecolor="none")
ax.gridlines(draw_labels=True, linewidth=0.4, linestyle="--", color="gray", alpha=0.6)

# Kontur threshold
cs = ax.contour(
    lon, lat, shear_annual_mean,
    levels=[8, 10],
    colors=["blue", "darkred"],
    linewidths=1.2,
    transform=ccrs.PlateCarree(),
)
ax.clabel(cs, fmt="%d m/s", fontsize=9)

cb = plt.colorbar(pcm, ax=ax, orientation="vertical", pad=0.04, shrink=0.85)
cb.set_label("Wind Shear 500–850 hPa (m/s)", fontsize=11)

ax.set_title(
    "Annual-Mean 500–850 hPa Wind Shear — Indonesia (ERA5, 2024)",
    fontsize=13, fontweight="bold"
)
ax.set_extent([95, 141, -11, 6], crs=ccrs.PlateCarree())

out = os.environ.get("EXPECT_IMAGE_PATH", "shear_map.png")
fig.savefig(out, dpi=130, bbox_inches="tight")
print("wrote", out)

snippet-3

Peta di atas memperlihatkan gradien shear yang khas di wilayah Indonesia. Area dengan shear rendah (hijau, < 8 m/s) umumnya berada di wilayah di mana pembentukan TC secara historis lebih sering terjadi. Sebaliknya, zona shear tinggi (merah, > 10 m/s) berkorelasi dengan aktivitas jet yang kuat atau pengaruh monsun.

Perlu diingat bahwa 500–850 hPa bukan DLS standar untuk analisis TC — threshold 8 dan 10 m/s di atas berasal dari studi 200–850 hPa. Gunakan nilai ini sebagai referensi komparatif, bukan sebagai angka operasional langsung.

Sebagai konteks nyata: pada Februari 2025, enam TC aktif secara bersamaan di Belahan Bumi Selatan — tiga di Samudra Pasifik selatan (Alfred, Rae, Seru) dan tiga di Samudra Hindia selatan (Bianca, Honde, Garance). Menurut NASA Earth Observatory, salah satu faktor pendukung proliferasi siklon yang luar biasa ini adalah kondisi shear rendah yang meluas di kedua basin tersebut, dikombinasikan dengan SST di atas normal.

False-color MODIS/VIIRS satellite image from 26 February 2025 showing six simultaneous tropical cyclones across the Southern Hemisphere Sumber: NASA Earth Observatory (Cyclone Flurry in the Southern Hemisphere)

Berikut adalah infografis dari NOAA/AOML yang menggambarkan mekanisme fisik di balik efek shear terhadap vortex TC — shear yang kuat memiringkan kolom konveksi, membawa udara kering dari luar ke dalam core badai.

Infographic showing how vertical wind shear tilts a tropical cyclone vortex and creates asymmetric eyewall structure Sumber: NOAA/AOML (Impact of Wind Shear on Tropical Cyclone Intensity)

Klasifikasi Rezim Shear untuk Prakiraan TC

Dengan shear magnitude di tangan, kita bisa mengklasifikasikan setiap grid cell ke dalam tiga rezim operasional dan menghitung fraksi area yang masuk masing-masing kategori sepanjang 2024.

import numpy as np
import pandas as pd

# Annual-mean shear per grid cell (sudah dihitung di snippet-3)
S = shear_annual_mean   # (lat, lon)
total = np.sum(~np.isnan(S))

fav  = np.sum(S < 8)                   / total * 100
marg = np.sum((S >= 8) & (S <= 10))   / total * 100
inh  = np.sum(S > 10)                  / total * 100

print("=== Klasifikasi Rezim Shear (Annual Mean, 2024) ===")
print(f"  Favorable  (< 8 m/s)  : {fav:5.1f}% dari total area domain")
print(f"  Marginal   (8–10 m/s) : {marg:5.1f}% dari total area domain")
print(f"  Inhibitory (> 10 m/s) : {inh:5.1f}% dari total area domain")
print()

# Monthly breakdown — per bulan, fraksi area favorable
time_dim = "valid_time" if "valid_time" in ds_u.dims else "time"
time_vals = ds_u[time_dim].values
months = pd.DatetimeIndex(time_vals).month

print("Monthly area-fraction favorable (shear < 8 m/s):")
for m in range(1, 13):
    mask = months == m
    if mask.sum() > 0:
        monthly_shear = np.nanmean(shear_mag[mask], axis=0)
        frac_fav = np.sum(monthly_shear < 8) / np.sum(~np.isnan(monthly_shear)) * 100
        bar = "#" * int(frac_fav / 2)
        print(f"  {m:02d}: {frac_fav:5.1f}%  {bar}")
=== Klasifikasi Rezim Shear (Annual Mean, 2024) ===
  Favorable  (< 8 m/s)  :  97.5% dari total area domain
  Marginal   (8–10 m/s) :   2.5% dari total area domain
  Inhibitory (> 10 m/s) :   0.0% dari total area domain

Monthly area-fraction favorable (shear < 8 m/s):
  01:  95.6%  ###############################################
  02:  99.9%  #################################################
  03:  98.7%  #################################################
  04:  98.2%  #################################################
  05:  72.7%  ####################################
  06:  90.8%  #############################################
  07:  94.0%  ###############################################
  08:  78.4%  #######################################
  09:  80.8%  ########################################
  10:  91.8%  #############################################
  11:  99.6%  #################################################
  12:  74.0%  #####################################

Hasil klasifikasi di atas menunjukkan berapa persen wilayah Indonesia (secara rata-rata tahunan) berada di rezim yang favorable, marginal, atau inhibitory. Variasi bulanan penting untuk diperiksa — bulan-bulan tertentu yang memiliki fraksi favorable lebih tinggi berkorelasi historis dengan aktivitas TC yang lebih aktif di dekat perairan Indonesia.

Dari perspektif perubahan iklim, NOAA Climate.gov menyebutkan bahwa proyeksi di beberapa region menunjukkan pengurangan deep-layer shear di masa depan — yang secara teori meningkatkan probabilitas rapid intensification sebelum landfall.

Perbandingan dengan GFS GRIB2 dan Langkah Selanjutnya

Kita telah menghitung shear dari ERA5 — dataset reanalisis yang sangat cocok untuk klimatologi dan validasi. Untuk analisis operasional real-time, data yang dipakai adalah output GFS dari NOMADS NCEP. Alurnya sebagai berikut:

Download GFS GRIB2 via NOMADS menggunakan URL kanonikal:

https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.YYYYMMDD/HH/atmos/gfs.tHHz.pgrb2.0p25.fFFF

di mana YYYYMMDD adalah tanggal siklus, HH adalah siklus runtime (00/06/12/18 UTC), dan FFF adalah forecast hour (000–384).

Agar tidak download file GRIB2 lengkap (beberapa GB per file), gunakan NOMADS GRIB2 filter tool di https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25.pl untuk subset hanya variabel UGRD dan VGRD di level lev_200_mb dan lev_850_mb. File subset hasil filter biasanya < 5 MB per forecast hour.

Setelah file ter-download, baca dengan cfgrib:

import xarray as xr

ds_gfs = xr.open_dataset(
    "gfs.t00z.pgrb2.0p25.f000",
    engine="cfgrib",
    filter_by_keys={"typeOfLevel": "isobaricInhPa", "shortName": ["u", "v"]},
)

Blok di atas bersifat ilustratif — membutuhkan file GFS lokal yang tidak tersedia di semua lingkungan. Perhatikan bahwa NOMADS hanya menyimpan sekitar 10 hari terakhir; untuk data historis GFS, gunakan AWS Open Data (s3://noaa-gfs-bdp-pds) atau NCAR RDA.

Yang sudah kita pelajari dalam tutorial ini:

  1. Cara mengunduh komponen u/v angin di pressure levels dari CDS menggunakan cdsapi dengan guard os.path.exists
  2. Menghitung wind shear 500–850 hPa menggunakan vector math sederhana dengan NumPy
  3. Memetakan distribusi spasial shear menggunakan matplotlib dan cartopy
  4. Mengklasifikasikan grid cells ke dalam rezim favorable/marginal/inhibitory berdasarkan threshold operasional CPC dan SHIPS/AOML

Ekstensi yang disarankan: - Hitung ensemble shear spread dari GFS ensemble (GEFS) untuk kuantifikasi ketidakpastian - Buat time-series anomali shear bulanan terhadap klimatologi untuk deteksi sinyal La Niña/El Niño - Korelasikan shear dengan RAMI (Rapid Intensification) events dari IBTrACS database - Bandingkan 500–850 hPa shear dengan 200–850 hPa DLS menggunakan ERA5 pressure level yang mencakup 200 hPa

Eksplorasi artikel meteorologi lainnya di meteo.my.id — kunjungi https://meteo.my.id.

Referensi

Tidak ada komentar:

Posting Komentar