Skip to content

Wonky 2m temperature data -- Extreme temperatures, hard boundaries, and visible icosahedral pattern #29

@s-zeng

Description

@s-zeng

Hi all,

I can't seem to get reasonable looking 2m temperature forecasts using graphcast. In all cases, the predicted temperatures inevitably get extreme (> 100 C ), and if you visualize the forecast there are both visible hard boundaries (very hot on one side of a line and very cold on another), as well as a visible icosahedral pattern. Please see the attached forecast image, as well as steps to reproduce it.

Reproduction steps

  1. First make forecast grib file:
$ ai-models --date 20250130 graphcast --download-assets --lead-time 360 --path 20250130_graphcast_control.grib

  1. Use the following script to generate an animated png:
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import os
import imageio.v3 as iio
from apng import APNG

forecast_grib_file = "20250130_graphcast_control.grib"
ds = xr.load_dataset(forecast_grib_file, filter_by_keys={"cfVarName": "t2m"})

temperature = ds["t2m"] - 273.15

lat = ds.latitude
lon = ds.longitude
time_steps = temperature["step"]

# Projection and plot extent (Europe bounding box)
projection = ccrs.PlateCarree()
extent = [-12, 35, 34, 72]

# Temporary folder setup
frame_folder = "hd_frames"
os.makedirs(frame_folder, exist_ok=True)
filenames = []

dpi = 200
fig_width = 3840 / dpi  # 3840 pixels width
fig_height = 2160 / dpi  # 2160 pixels height

for i, step in enumerate(time_steps):
    fig = plt.figure(figsize=(fig_width, fig_height), dpi=dpi)
    ax = plt.axes(projection=projection)
    ax.set_extent(extent)
    # map features
    ax.add_feature(cfeature.COASTLINE.with_scale("50m"), linewidth=0.7)
    ax.add_feature(cfeature.BORDERS.with_scale("50m"), linestyle=":", linewidth=0.5)
    # temperature plot
    temp_plot = ax.pcolormesh(
        lon,
        lat,
        temperature.sel(step=step),
        cmap="coolwarm",
        shading="auto",
        vmin=-40,
        vmax=50,
    )
    # Title and colorbar adjustments
    cb = plt.colorbar(temp_plot, orientation="vertical", pad=0.02, shrink=0.7)
    cb.set_label("2m Temperature (°C)", fontsize=20)
    cb.ax.tick_params(labelsize=18)
    plt.title(
        f"2m Temperature (°C) - Step: {np.array(6*int(step)/21600000000000)} hours",
        fontsize=24,
        pad=15,
    )
    # Save the frame
    filename = f"{frame_folder}/frame_{i:03d}.png"
    plt.savefig(filename, bbox_inches="tight")
    filenames.append(filename)
    plt.close()

output_file = "temperature_europe_4k.mp4"
fps = 3  # frames per second (~0.3 sec/frame)

# Read frames and determine video size
frames = [iio.imread(filename) for filename in filenames]

# Save as MP4
iio.imwrite(output_file, frames, fps=fps, codec="libx264", quality=8)

# Clean up
for filename in filenames:
    os.remove(filename)
os.rmdir(frame_folder)

I then downsampled to 720p with ffmpeg to fit within github upload restraints

20250130_graphcast_t2m.mp4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions