TANGERANG SELATAN WEATHER

Rabu, 24 Juni 2026

Menghitung Suhu Potensial dari ERA5

Latitude-pressure cross section of potential temperature (theta) in February, showing isentropic structure from pole to tropics

Sumber: NOAA Climate Prediction Center, Stratospheric Research Group (Isentropic Analysis)

Kenapa Suhu Potensial Penting

Bayangkan sebuah parsel udara di atas Jawa yang perlahan naik ke ketinggian 5 km. Suhu udara itu turun — bukan karena kehilangan panas, melainkan karena tekanan atmosfer berkurang sehingga parsel berekspansi. Kalau kita hanya melihat suhu biasa (temperature), kita tidak bisa membedakan apakah perubahan itu akibat gerakan adiabatik atau pertukaran panas sejati dengan lingkungan sekitar.

Di sinilah potential temperature (suhu potensial), biasa dilambangkan \(\theta\), menjadi alat yang sangat berguna. Jika udara naik atau turun tanpa pertukaran panas, bagaimana kita masih bisa mengetahui dari mana asalnya? Jawabannya: \(\theta\) tetap konstan dalam proses adiabatik kering. Setiap parsel udara "membawa" nilai \(\theta\)-nya seperti sidik jari. Dengan melacak bidang isentropis (permukaan \(\theta\) = konstan), kita bisa menelusuri jalur pergerakan massa udara meskipun ketinggiannya berubah drastis.

NOAA Climate Prediction Center menggunakan pendekatan ini untuk memantau pergerakan udara di stratosfer, termasuk melacak deplesi ozon saat musim dingin di kutub. Analisis isentropis juga menjadi fondasi untuk menghitung CAPE dan CIN, dua parameter ketidakstabilan atmosfer yang kritis untuk prakiraan konveksi dan cuaca ekstrem.

Dalam tutorial ini, kita download data temperature ERA5 pada dua level tekanan (500 dan 850 hPa) untuk wilayah Indonesia, hitung \(\theta\) secara vectorized menggunakan xarray dan NumPy, lalu buat penampang vertikal meridional untuk melihat struktur isentropisnya secara langsung.

Rumus Suhu Potensial dan Setup Data

Formula untuk potential temperature sudah dikenal sejak akhir abad ke-19, diturunkan dari persamaan Poisson untuk proses adiabatik:

$$\theta = T \left(\frac{P_0}{P}\right)^{\kappa}$$

Di sini: - \(T\) adalah suhu dalam Kelvin - \(P\) adalah tekanan dalam hPa - \(P_0 = 1000\ \text{hPa}\) adalah tekanan referensi standar - \(\kappa = R_d / c_p\) adalah konstanta Poisson

Untuk udara kering, \(R_d \approx 287\ \text{J/(kg·K)}\) dan \(c_p \approx 1004\ \text{J/(kg·K)}\), sehingga \(\kappa \approx 2/7 \approx 0{,}2857\). Dalam praktik, nilai \(0{,}286\) sering digunakan sebagai aproksimasi; ECMWF sendiri menggunakan \(0{,}28571\) dalam model IFS mereka. Kita pakai nilai eksak \(2/7\) yang sesuai konvensi MetPy dan ECMWF.

Sebagai sanity check yang berguna: parsel dengan \(T = 273\ \text{K}\) di level 850 hPa akan memiliki \(\theta \approx 286\ \text{K}\) — artinya parsel itu akan lebih panas sekitar 13 K jika kita bawa adiabatik ke permukaan referensi 1000 hPa. Intuisi ini berguna untuk memverifikasi hasil komputasi kita.

ERA5 menyediakan variabel temperature pada pressure levels dalam satuan Kelvin, tersedia di 37 level tekanan mulai dari 1000 hingga 1 hPa. Untuk tutorial ini, kita download data temperature di 500 dan 850 hPa untuk Indonesia sepanjang tahun 2024. Snippet berikut melakukan download dari CDS (hanya dijalankan sekali jika file belum ada) dan langsung membuka dataset-nya:

import os
import cdsapi
import xarray as xr

OUT = "era5_t_pl500-850_indonesia_2024_d.nc"
if not os.path.exists(OUT):
    c = cdsapi.Client(quiet=True)
    c.retrieve(
        "reanalysis-era5-pressure-levels",
        {
            "product_type": "reanalysis",
            "variable": ["temperature"],
            "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,
    )
ds = xr.open_dataset(OUT)
print(ds)
<xarray.Dataset> Size: 37MB
Dimensions:         (valid_time: 366, pressure_level: 2, latitude: 69,
                     longitude: 185)
Coordinates:
  * valid_time      (valid_time) datetime64[ns] 3kB 2024-01-01 ... 2024-12-31
    expver          (valid_time) <U4 6kB ...
  * pressure_level  (pressure_level) float64 16B 850.0 500.0
  * latitude        (latitude) float64 552B 6.0 5.75 5.5 ... -10.5 -10.75 -11.0
  * longitude       (longitude) float64 1kB 95.0 95.25 95.5 ... 140.8 141.0
    number          int64 8B ...
Data variables:
    t               (valid_time, pressure_level, latitude, longitude) float32 37MB ...
Attributes:
    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-10T04:10 GRIB to CDM+CF via cfgrib-0.9.1...

Output di atas menampilkan struktur dataset ERA5: dimensi valid_time (seluruh hari di 2024), pressure_level (dua nilai: 500 dan 850 hPa), latitude, dan longitude dengan bounding box Indonesia. Variabel utamanya adalah t — temperature dalam Kelvin.

Menghitung Theta Adiabatik untuk Semua Grid

Keunggulan xarray adalah kemampuannya untuk melakukan broadcasting secara otomatis antar dimensi. Kita tidak perlu loop manual: operasi \(\theta = T \times (P_0 / P)^\kappa\) bisa langsung diterapkan ke seluruh DataArray sekaligus, dan xarray secara otomatis menyelaraskan dimensi pressure_level dengan koordinat yang benar.

Nilai \(\kappa = 2/7\) kita pakai sebagai bilangan rasional eksak daripada float desimal, menghindari akumulasi kesalahan pembulatan saat dikalikan ke ribuan titik grid:

import numpy as np

P0 = 1000.0   # referensi tekanan dalam hPa
kappa = 2 / 7  # Rd/cp untuk udara kering (konvensi ECMWF: 0.28571)

# Ambil variabel temperature (dalam Kelvin) dan koordinat pressure_level
T = ds["t"]                    # shape: (time, pressure_level, latitude, longitude)
P = ds["pressure_level"]       # shape: (pressure_level,) dalam hPa

# xarray broadcast P ke semua dimensi T secara otomatis
theta = T * (P0 / P) ** kappa
theta.name = "theta"
theta.attrs["units"] = "K"
theta.attrs["long_name"] = "Potential Temperature"

# Verifikasi: ambil sampel di waktu pertama, satu titik grid
print("Suhu potensial pada waktu pertama (K):")
for lev in theta.pressure_level.values:
    val = float(theta.isel(valid_time=0, latitude=10, longitude=10).sel(pressure_level=lev))
    T_val = float(T.isel(valid_time=0, latitude=10, longitude=10).sel(pressure_level=lev))
    print(f"  {int(lev):4d} hPa  T = {T_val:.2f} K  →  θ = {val:.2f} K")
Suhu potensial pada waktu pertama (K):
   850 hPa  T = 291.16 K  →  θ = 305.00 K
   500 hPa  T = 268.89 K  →  θ = 327.78 K

Output di atas memperlihatkan nilai \(\theta\) pada dua level tekanan untuk satu titik grid. Perhatikan bahwa \(\theta\) di 850 hPa lebih tinggi dari \(T\)-nya (karena parsel itu "harus dipanaskan" bila dibawa ke 1000 hPa), sementara di 500 hPa perbedaannya lebih besar lagi karena tekanannya jauh lebih rendah. Inilah property konservasi yang kita cari: dua parsel dengan \(\theta\) yang sama berasal dari "akar adiabatik" yang sama, meski sekarang berada di ketinggian berbeda.

Visualisasi Theta dalam Penampang Vertikal

Dengan hanya dua level tekanan (500 dan 850 hPa), kita bisa membuat penampang meridional yang menampilkan distribusi \(\theta\) sepanjang garis bujur 115°E — memotong Borneo, Jawa, hingga selatan Indonesia. Irisan ini memungkinkan kita melihat bagaimana nilai \(\theta\) bervariasi terhadap lintang dan ketinggian.

Karena hanya ada dua level, kita gunakan pcolormesh untuk visualisasi filled background dan scatter untuk menandai nilai aktual di setiap level — lebih jujur daripada menginterpolasi kontur di antara dua titik saja:

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

# Rata-rata theta sepanjang waktu, ambil irisan meridional di sekitar 115°E
theta_mean = theta.mean("valid_time")
lon_idx = int(np.abs(theta_mean.longitude.values - 115.0).argmin())
cross = theta_mean.isel(longitude=lon_idx)  # shape: (pressure_level, latitude)

lats = cross.latitude.values
levels = cross.pressure_level.values  # [500, 850] hPa

fig, ax = plt.subplots(figsize=(10, 5))

# Warna latar untuk setiap level tekanan
colors = ["#4575b4", "#d73027"]  # biru = 500 hPa (lebih tinggi θ), merah = 850 hPa
for i, (lev, color) in enumerate(zip(levels, colors)):
    vals = cross.sel(pressure_level=lev).values
    ax.plot(lats, vals, color=color, linewidth=2.0,
            label=f"{int(lev)} hPa  (θ rerata {vals.mean():.1f} K)")
    ax.fill_between(lats, vals, alpha=0.15, color=color)

ax.set_xlabel("Lintang (°)", fontsize=12)
ax.set_ylabel("θ (K)", fontsize=12)
ax.set_title("Potential Temperature θ — Penampang Meridional 115°E\nRerata Harian 2024 (ERA5, Indonesia)", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, linestyle="--", alpha=0.5)
ax.set_xlim(lats.min(), lats.max())
plt.tight_layout()
plt.savefig("snippet-3-1.webp", dpi=120)
print("snippet-3-1.webp")

Line plot of potential temperature at 500 and 850 hPa versus latitude along 115 degrees East, averaged over 2024

Plot di atas menampilkan profil \(\theta\) rata-rata sepanjang 2024 pada dua level tekanan, sepanjang garis bujur 115°E. Beberapa pola menarik yang kita harapkan terlihat: nilai \(\theta\) di 500 hPa secara konsisten lebih tinggi daripada di 850 hPa (artinya lapisan atas lebih stabil secara potensial terhadap lapisan bawah). Gradien \(\theta\) terhadap lintang yang relatif kecil di wilayah tropis mencerminkan karakteristik atmosfer tropis yang hampir barotropik — berbeda dengan mid-latitudes di mana gradien \(\theta\) jauh lebih tajam.

Analisis Isentropic dan Interpretasi

Setelah kita punya field \(\theta\) lengkap, pertanyaan yang lebih menarik muncul: pada level tekanan berapa isentrope \(\theta = 300\ \text{K}\) berada di atas Indonesia? Isentrope ini penting karena mewakili batas bawah yang khas antara lapisan campuran (mixed layer) dan lapisan stabil di atas Jawa dan Borneo.

Perlu diingat prinsip dasarnya: dalam proses adiabatik kering, entropy berbanding lurus dengan \(\theta\), sehingga "entropy is directly proportional to potential temperature" — parsel udara yang bergerak di sepanjang permukaan \(\theta = \text{konstan}\) tidak mengalami pertukaran panas dengan lingkungannya. Prinsip inilah yang membuat isentropis menjadi "jalur alami" pergerakan massa udara dalam atmosfer bebas.

Karena dataset kita hanya memiliki dua level (500 dan 850 hPa), kita identifikasi di level mana \(\theta\) paling dekat ke 300 K, lalu ambil statistik distribusinya di seluruh domain:

import numpy as np

TARGET_THETA = 300.0  # K — isentrope khas untuk atmosfer tropis bawah

# Hitung jarak absolut ke target di setiap grid dan waktu
diff = np.abs(theta - TARGET_THETA)  # shape: (time, pressure_level, lat, lon)

# Temukan index level yang paling dekat ke 300 K, per titik grid dan waktu
nearest_idx = diff.argmin(dim="pressure_level")  # shape: (time, lat, lon), nilai 0 atau 1

# Presisi level: 0 = 500 hPa, 1 = 850 hPa (tergantung urutan pressure_level)
plevels = theta.pressure_level.values  # [500., 850.] atau [850., 500.]
print(f"Urutan level dalam dataset: {plevels} hPa")

# Rata-rata nearest_idx terhadap waktu
avg_idx = nearest_idx.mean("valid_time")  # nilai 0.0 berarti selalu 500 hPa, 1.0 = selalu 850 hPa
frac_850 = float((nearest_idx == 1).mean("valid_time").mean())
frac_500 = float((nearest_idx == 0).mean("valid_time").mean())

print(f"\nIsentrope θ = {TARGET_THETA} K ditemukan lebih dekat ke:")
print(f"  500 hPa: {frac_500*100:.1f}% dari semua titik grid × waktu")
print(f"  850 hPa: {frac_850*100:.1f}% dari semua titik grid × waktu")

# Hitung θ aktual di 850 hPa dan 500 hPa untuk konteks
theta_850 = float(theta.sel(pressure_level=850).mean())
theta_500 = float(theta.sel(pressure_level=500).mean())
print(f"\nRerata θ domain sepanjang 2024:")
print(f"  850 hPa: {theta_850:.1f} K")
print(f"  500 hPa: {theta_500:.1f} K")
print(f"\nKesimpulan: isentrope θ = {TARGET_THETA} K berada {'di antara' if theta_850 < TARGET_THETA < theta_500 else 'di luar rentang'} 850–500 hPa.")
Urutan level dalam dataset: [850. 500.] hPa

Isentrope θ = 300.0 K ditemukan lebih dekat ke:
  500 hPa: 100.0% dari semua titik grid × waktu
  850 hPa: 0.0% dari semua titik grid × waktu

Rerata θ domain sepanjang 2024:
  850 hPa: 305.4 K
  500 hPa: 327.8 K

Kesimpulan: isentrope θ = 300.0 K berada di luar rentang 850–500 hPa.

Output snippet-4 memberikan gambaran kuantitatif posisi isentrope \(\theta = 300\ \text{K}\) di wilayah Indonesia. Rerata domain menunjukkan \(\theta\) di 850 hPa sudah mencapai 305{,}4 K, artinya isentrope 300 K berada di bawah level 850 hPa — di lapisan troposfer paling bawah, sekitar 900–950 hPa di atas Indonesia. Ini masuk akal: atmosfer tropis Indonesia hangat dan lembap, sehingga udara dekat permukaan sudah memiliki \(\theta\) yang cukup tinggi meskipun secara teknik berada di lapisan batas (boundary layer).

Parsel udara yang bergerak sepanjang isentrope ini — misalnya udara maritim yang mengalir dari Samudra Hindia menuju pantai barat Sumatra — dalam kondisi ideal tidak bertukar panas dengan sekitarnya. Analisis isentropis memungkinkan kita "mengikuti" massa udara tersebut bahkan ketika jalurnya melintasi batas-batas level tekanan yang kita gunakan.

Langkah Selanjutnya

Tutorial ini memperkenalkan komputasi \(\theta\) dari ERA5 sebagai langkah pertama dalam analisis termodinamika atmosfer. Ada beberapa arah yang menarik untuk dieksplorasi lebih lanjut:

Equivalent potential temperature (\(\theta_e\)) memperluas konsep yang sama ke udara lembap. Alih-alih mengabaikan kandungan air, \(\theta_e\) memperhitungkan panas laten kondensasi — sangat relevan untuk atmosfer tropis Indonesia yang kaya uap air. Perbedaan antara \(\theta\) dan \(\theta_e\) langsung mencerminkan kandungan moisture massa udara.

Diagnosa stabilitas menjadi jauh lebih tepat saat menggunakan \(\theta\) daripada suhu biasa. Kalau \(\theta\) meningkat terhadap ketinggian (\(\partial\theta/\partial z > 0\)), lapisan itu stabil secara adiabatik kering. Profil \(\theta\) dari ERA5 bisa langsung dibandingkan dengan profil radiosonde untuk validasi model.

Output GFS real-time menggunakan format dan konvensi yang sangat mirip ERA5 pada pressure levels. Pola yang sama — buka NetCDF, ambil variabel temperature, hitung \(\theta\) dengan formula Poisson — berlaku langsung untuk data GFS yang kita download lewat NOMADS atau Open-Meteo. Ini memungkinkan perbandingan antara analisis ERA5 dengan prakiraan numerik cuaca terbaru.

Potential temperature adalah fondasi yang solid. Dari sini, CAPE dan CIN, analisis frontal, dan diagnosa konveksi semuanya menjadi lebih mudah dipahami secara fisis.

Eksplorasi artikel meteorologi lainnya di meteo.my.id — buka di sini.

Referensi

Tidak ada komentar:

Posting Komentar