Skip to article frontmatterSkip to article content

Acceso a pronósticos GFS en la nube


Modelo de pronóstico global mostrando campos atmosféricos

Introducción

En este cuaderno aprenderás a acceder y analizar pronósticos del Global Forecast System (GFS) utilizando ArrayLake, un servicio de repositorios Zarr en la nube que proporciona acceso eficiente a datos de modelos de pronóstico.

GFS es el modelo de pronóstico numérico del tiempo operado por el Centro Nacional de Predicción Ambiental (NCEP) de Estados Unidos. Genera pronósticos de hasta 16 días para docenas de variables atmosféricas y de superficie terrestre, incluyendo temperatura, vientos, precipitación, humedad y nubosidad. El modelo se ejecuta 4 veces al día (00z, 06z, 12z, 18z) y es ampliamente utilizado como condición inicial para modelos regionales.

Los datos que utilizaremos provienen del repositorio earthmover-public/gfs en ArrayLake, que contiene pronósticos del GFS en formato Zarr v3 / Icechunk con resolución de 0.25° (~28 km). El grupo solar incluye variables clave para aplicaciones meteorológicas y de energía renovable.

📚 Descripción general

En este cuaderno aprenderás a:

  1. Comprender qué es el modelo GFS y su importancia en pronóstico meteorológico

  2. Acceder a pronósticos GFS en formato Zarr v3 mediante ArrayLake

  3. Explorar variables de superficie relevantes para meteorología operacional

  4. Generar mapas de pronóstico para regiones específicas (ej. Colombia)

  5. Visualizar series temporales de pronóstico para ubicaciones puntuales


✅ Requisitos previos

ConceptosImportanciaNotas
Introducción a XarrayNecesarioManipulación de arreglos multidimensionales
Xarray: Lectura de datosNecesarioApertura de conjuntos de datos Zarr
CartopyNecesarioVisualización de mapas y proyecciones
Introducción a DatetimeÚtilManejo de estampas de tiempo
Formato ZarrÚtilComprensión de formatos cloud-nativos
Conceptos de pronóstico numéricoÚtilInterpretación de salidas de modelos

⏱️ Tiempo estimado de aprendizaje: 30–40 minutos

✍️ Formato: Interactivo


Librerías

Importamos las librerías necesarias para trabajar con ArrayLake y visualizar pronósticos.

from arraylake import Client
import xarray as xr
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from datetime import datetime, timedelta

Autenticación con ArrayLake

ArrayLake es un servicio de repositorios Zarr en la nube que proporciona acceso eficiente a grandes datasets como GFS. Para usar ArrayLake:

  1. En Binder/JupyterHub: Ejecuta client.login() y sigue las instrucciones para autenticarte

  2. En GitHub Actions: Las credenciales se gestionan mediante secrets del repositorio

client = Client()
client.login()  # Solo necesario la primera vez por sesión
Loading...
repo = client.get_repo("earthmover-public/gfs")

# Establecer vista de solo lectura del branch "main" inmutable
session = repo.readonly_session("main")

1. 🌍 Introducción al modelo GFS

El Global Forecast System (GFS) es el modelo de pronóstico numérico del tiempo operado por el Centro Nacional de Predicción Ambiental (NCEP) de Estados Unidos.

1.1. 📌 Características principales

  • Cobertura global: Pronósticos para todo el planeta

  • ⏱️ Frecuencia de ejecución: 4 veces al día (00z, 06z, 12z, 18z)

  • 📅 Alcance del pronóstico: Hasta 16 días

  • 🌐 Resolución espacial: 0.25° (~28 km)

  • 📈 Niveles verticales: 127 capas en la atmósfera

  • 🔢 Sistema de grilla: Esfera cúbica de volumen finito (FV3)

1.2. 📎 Aplicaciones

  • 🌦️ Pronóstico meteorológico operacional

  • 🌊 Condiciones iniciales para modelos regionales (WRF, etc.)

  • ☀️ Predicción de generación de energía solar y eólica

  • ✈️ Planificación de aviación y navegación marítima

  • 🌾 Agricultura y gestión de recursos hídricos

💡 Nota: GFS es ampliamente utilizado como condición inicial y de frontera para modelos regionales de mayor resolución.

2. ☁️ Acceso a datos GFS con ArrayLake

El conjunto de datos GFS está disponible a través de ArrayLake en el repositorio earthmover-public/gfs. Esta versión contiene:

  • Variables del grupo “solar”: temperatura 2m, nubosidad, humedad, precipitación, ráfagas

  • 📅 Periodo: Mayo 2024 - presente (actualizado cada 6 horas)

  • 🌐 Resolución espacial: 0.25° (1440×721 puntos)

  • ⏱️ Resolución temporal: Horaria, pronósticos hasta 16 días

  • 💾 Formato: Zarr v3 / Icechunk

Variables disponibles en el grupo “solar”

VariableDescripciónUnidades
t2mTemperatura a 2 metrosK
r2Humedad relativa a 2 metros%
tccCobertura de nubes totalfracción (0-1)
prateTasa de precipitaciónkg/m²/s
gustRáfaga de vientom/s

2.1. 🔓 Apertura del conjunto de datos

%%time
ds_gfs = xr.open_dataset(
    session.store,
    engine="zarr",
    consolidated=False,
    zarr_format=3,
    chunks={},
    group="solar"  # Grupo con variables de superficie
)
display(ds_gfs)

2.2. 📋 Exploración del conjunto de datos

El conjunto de datos contiene:

  • 5 variables de superficie (t2m, r2, tcc, prate, gust)

  • 📐 Dimensiones: time × latitude (721) × longitude (1440)

  • 🌍 Coordenadas: latitudes -90° → 90°, longitudes 0° → 360°

  • 💾 Formato: Zarr v3 / Icechunk optimizado para consultas en la nube

3. 🗺️ Visualización de pronósticos

Comencemos visualizando el pronóstico de temperatura para el día de mañana.

3.1. 🌍 Mapa global de temperatura

# Calcular fecha de mañana
tomorrow = datetime.now() + timedelta(days=1)
fecha_str = f"{tomorrow:%Y-%m-%d}"

print(f"Pronóstico para: {fecha_str}")
# Seleccionar temperatura para mañana al mediodía
t2m_forecast = ds_gfs.t2m.sel(time=f"{fecha_str} 12:00", method="nearest")

# Convertir de Kelvin a Celsius
t2m_celsius = t2m_forecast - 273.15
t2m_celsius
# Creamos una visualizacion 
fig, ax = plt.subplots(figsize=(12, 6))
t2m_celsius.isel(step=10).plot(ax=ax, x="longitude", y="latitude", cmap="RdYlBu_r", robust=True)
ax.set_title(f"Temperatura a 2m - Pronóstico GFS ({fecha_str} 12:00 UTC)", fontsize=14)
ax.set_xlabel("Longitud [°E]")
ax.set_ylabel("Latitud [°N]")
plt.tight_layout()
plt.show()

3.2. 🇨🇴 Pronóstico regional para Colombia

Ahora extraigamos y visualicemos el pronóstico para Colombia usando una proyección apropiada.

# Seleccionar región de Colombia
# Longitud: 275° a 300° (equivalente a -85° a -60°)
# Latitud: 14° a -5° (Norte a Sur)
gfs_colombia = ds_gfs.sel(
    longitude=slice(275, 300),
    latitude=slice(14, -5)).sel(
    time=f"{fecha_str} 12:00",
    method="nearest"
)

print(f"Shape Colombia: {gfs_colombia.t2m.shape}")
gfs_colombia
# Crear mapa para Colombia con proyección PlateCarree
fig, ax = plt.subplots(
    # figsize=(10, 8),
    subplot_kw={"projection": ccrs.PlateCarree()},
    dpi=150
)

# Temperatura en Celsius
t2m_col = gfs_colombia.t2m - 273.15

# Graficar temperatura
t2m_col.isel(step=0).plot.contourf(
    ax=ax,
    x="longitude", 
    y="latitude",
    cmap="RdYlBu_r",
    transform=ccrs.PlateCarree(),
    cbar_kwargs={
        "label": "Temperatura [°C]",
        "orientation": "horizontal",
        "shrink": 0.8
    }
)

# Añadir características geográficas
ax.coastlines()
ax.add_feature(cfeature.BORDERS, linestyle=":")
ax.gridlines(draw_labels=True, linewidth=0.5, alpha=0.5)

ax.set_title(f"Pronóstico GFS - Colombia ({fecha_str} 12:00 UTC)", fontsize=12)
plt.show()

3.3. 📊 Múltiples variables para Colombia

Visualicemos varias variables meteorológicas simultáneamente.

# Crear panel con 4 variables
fig, axes = plt.subplots(
    2, 2,
    figsize=(8, 6),
    subplot_kw={"projection": ccrs.PlateCarree()},
    dpi=120
)
axes = axes.flatten()

# Variable 1: Temperatura
(gfs_colombia.t2m.isel(step=0) - 273.15).plot(
    x="longitude", y="latitude",
    ax=axes[0], cmap="RdYlBu_r", transform=ccrs.PlateCarree(),
    cbar_kwargs={"label": "Temperatura [°C]", "shrink": 0.8}
)
axes[0].set_title("Temperatura 2m")

# Variable 2: Humedad relativa
gfs_colombia.r2.isel(step=0).plot(
    x="longitude", y="latitude",
    ax=axes[1], cmap="YlGnBu", transform=ccrs.PlateCarree(),
    cbar_kwargs={"label": "Humedad relativa [%]", "shrink": 0.8}
)
axes[1].set_title("Humedad relativa 2m")

# Variable 3: Cobertura de nubes
(gfs_colombia.isel(step=0).tcc * 100).plot(
    x="longitude", y="latitude",
    ax=axes[2], cmap="gray_r", transform=ccrs.PlateCarree(),
    cbar_kwargs={"label": "Cobertura [%]", "shrink": 0.8}
)
axes[2].set_title("Cobertura de nubes total")

# Variable 4: Precipitación
(gfs_colombia.isel(step=0).prate * 86400).plot(  # Convertir a mm/día
    x="longitude", y="latitude",
    ax=axes[3], cmap="Blues", transform=ccrs.PlateCarree(),
    vmin=0, vmax=100,
    cbar_kwargs={"label": "Precipitación [mm/día]", "shrink": 0.8}
)
axes[3].set_title("Tasa de precipitación")

# Añadir características a todos los mapas
for ax in axes:
    ax.coastlines()
    ax.add_feature(cfeature.BORDERS, linestyle=":")
    ax.gridlines(alpha=0.3)

plt.suptitle(f"Pronóstico GFS - Colombia ({fecha_str} 12:00 UTC)", fontsize=16, y=0.98)
plt.tight_layout()
plt.show()

4. ⏱️ Series temporales de pronóstico

Extraigamos una serie temporal del pronóstico para una ciudad específica.

4.1. 📈 Pronóstico para Bogotá

Extraigamos el pronóstico de temperatura para Bogotá durante los próximos 7 días.

# Coordenadas de Bogotá: 4.7°N, 285.9°E (-74.1°W)
today = datetime.now()
week_ahead = timedelta(hours=168)

t2m_bogota = ds_gfs.t2m.sel(
    latitude=4.7,
    longitude=285.9,
    time=f"{today}",
    method="nearest"
).sel(step=slice(None, week_ahead))

# Convertir a Celsius
t2m_bogota_celsius = t2m_bogota - 273.15

print(f"Pronóstico para Bogotá: {len(t2m_bogota_celsius)} pasos de tiempo")
t2m_bogota
fig, ax = plt.subplots(figsize=(12, 5))

t2m_bogota_celsius.plot(ax=ax, linewidth=1.5, color="steelblue")

ax.set_title("Pronóstico de temperatura - Bogotá (próximos 7 días)", fontsize=14)
ax.set_xlabel("Fecha")
ax.set_ylabel("Temperatura [°C]")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

✏️ Ejercicios

Ejercicio 1: Explora otra variable

Objetivo: Practicar visualización de otras variables del GFS.

Tareas:

  1. Genera un mapa de ráfagas de viento (gust) para Colombia

  2. Calcula la precipitación acumulada de 24 horas

  3. Visualiza la evolución temporal de nubosidad para Medellín (lat=6.25, lon=284.5)

# Tu código aquí
# Tarea 1: Mapa de ráfagas de viento para Colombia
fig, ax = plt.subplots(
    figsize=(10, 8),
    subplot_kw={'projection': ccrs.PlateCarree()},
    dpi=120
)

# Seleccionar ráfagas de viento
gust_col = gfs_colombia.gust.isel(step=0)

# Graficar
gust_col.plot(
    x='longitude',
    y='latitude',
    ax=ax,
    cmap='YlOrRd',
    transform=ccrs.PlateCarree(),
    cbar_kwargs={'label': 'Ráfagas de viento [m/s]', 'shrink': 0.8}
)

ax.coastlines()
ax.add_feature(cfeature.BORDERS, linestyle=':')
ax.gridlines(draw_labels=True, linewidth=0.5, alpha=0.5)
ax.set_title(f'Pronóstico de ráfagas de viento - Colombia ({fecha_str} 12:00 UTC)')
plt.show()
# Tarea 2: Precipitación acumulada de 24 horas
# Seleccionar las primeras 24 horas de pronóstico
precip_24h = gfs_colombia.prate.isel(step=slice(0, 24))

# Convertir de kg/m²/s a mm/día y sumar sobre 24 horas
# 1 kg/m²/s * 3600 s/h = mm/h, luego sumar 24 horas
precip_acum_24h = (precip_24h * 3600).sum(dim='step')

# Visualizar
fig, ax = plt.subplots(
    figsize=(10, 8),
    subplot_kw={'projection': ccrs.PlateCarree()},
    dpi=120
)

precip_acum_24h.plot(
    x='longitude',
    y='latitude',
    ax=ax,
    cmap='Blues',
    transform=ccrs.PlateCarree(),
    cbar_kwargs={'label': 'Precipitación acumulada [mm]', 'shrink': 0.8}
)

ax.coastlines()
ax.add_feature(cfeature.BORDERS, linestyle=':')
ax.gridlines(draw_labels=True, linewidth=0.5, alpha=0.5)
ax.set_title(f'Precipitación acumulada 24h - Colombia ({fecha_str})')
plt.show()

print(f'Precipitación máxima en 24h: {float(precip_acum_24h.max().values):.1f} mm')
# Tarea 3: Evolución temporal de nubosidad para Medellín
# Coordenadas: lat=6.25, lon=284.5 (equivalente a -75.5°W)
week_ahead = timedelta(hours=168)

tcc_medellin = ds_gfs.tcc.sel(
    latitude=6.25,
    longitude=284.5,
    time=f"{today}",
    method='nearest'
).sel(step=slice(None, week_ahead))

# Convertir a porcentaje
tcc_medellin_pct = tcc_medellin * 100

# Visualizar
fig, ax = plt.subplots(figsize=(12, 5))

tcc_medellin_pct.plot(ax=ax, linewidth=1.5, color='gray')

ax.set_title('Pronóstico de cobertura de nubes - Medellín (próximos 7 días)', fontsize=14)
ax.set_xlabel('Paso de tiempo')
ax.set_ylabel('Cobertura de nubes [%]')
ax.set_ylim(0, 100)
ax.grid(True, alpha=0.3)
ax.axhline(y=50, color='orange', linestyle='--', alpha=0.5, label='50% cobertura')
ax.legend()
plt.tight_layout()
plt.show()

print(f'Cobertura promedio: {float(tcc_medellin_pct.mean().values):.1f}%')
print(f'Cobertura máxima: {float(tcc_medellin_pct.max().values):.1f}%')
print(f'Cobertura mínima: {float(tcc_medellin_pct.min().values):.1f}%')

**Notas sobre la solución:**

- **Tarea 1**: Utilizamos el colormap `'YlOrRd'` (amarillo-naranja-rojo) apropiado para ráfagas de viento
- **Tarea 2**: Convertimos `prate` (kg/m²/s) a mm acumulados multiplicando por 3600 s/h y sumando sobre 24 pasos horarios
- **Tarea 3**: Graficamos la evolución temporal de nubosidad con una línea de referencia en 50% de cobertura

💡 **Pista**: Experimenta modificando los rangos de tiempo (`step`) o seleccionando diferentes ubicaciones para explorar distintas condiciones meteorológicas.

✅ Resumen

En este cuaderno aprendimos a:

✔️ Comprender las características del modelo GFS y su importancia operacional ✔️ Acceder a pronósticos GFS mediante ArrayLake en formato Zarr ✔️ Explorar variables de superficie relevantes para meteorología ✔️ Generar mapas regionales de pronóstico con proyecciones cartográficas ✔️ Extraer y visualizar series temporales para ubicaciones específicas

🚀 ¿Qué sigue?

Con los conocimientos sobre pronósticos GFS, puedes explorar:

Proyecto sugerido:

Desarrolla un sistema de monitoreo que:

  1. Descargue el último pronóstico GFS cada 6 horas

  2. Genere mapas automáticos para Colombia

  3. Compare con observaciones de estaciones del IDEAM

  4. Calcule métricas de error (RMSE, bias) del pronóstico