Tech/ 快速下载逐日ERA5数据
Published:
ERA5数据通常在CDS平台进行下载,可以直接获取monthly和hourly两种数据,如果需要daily数据,需要从hourly数据再次计算。我之前参考这个链接,利用CDS平台的workflow功能直接下载daily数据,可以节省存储空间和时间。然而,近日(9月26日)CDS平台进行了一次迁移升级,升级版本和账号是小事,但关键在于workflow功能不再可用,这意味着必须先下载hourly数据再计算daily。此外,下载数据的排队时间也显著变长:尝试在新系统仅下载一个hour的全球单层变量,就排队了两个小时。
经过朋友的启发,想到一个邪道方法是从weatherbench下载ERA5数据。weatherbench是用来训练数据驱动天气预报模型的基准数据集,目前已经出到第二版,这是他们的文档。可以看到,他们的数据也是在CDS下载后整理的,时间范围是1959-2023,时间频次为6h,空间分辨率为0.25˚,提供13个气压层和37个气压层两种版本的数据。具体的变量可以点开文档中的 Data variables
查看,共有62个变量。
数据可以通过 xarray
库在线access,为了访问Google Cloud bucket,还需要额外安装两个库:gcsfs
和 fsspec
配置好环境后,我们可以直接访问这个数据集,首先access到整个数据集:
import xarray as xr
ds = xr.open_zarr('gs://weatherbench2/datasets/era5/1959-2023_01_10-wb13-6h-1440x721_with_derived_variables.zarr')
这里实际上只下载了元数据的信息,没有下载任何数据,所以不会花费多少时间。如果访问某个具体的slice,例如:
ds_sel = ds.sel(level=500, time='2010-01-01').isel(time=0).geopotential.plot()
才会下载请求的数据。获取的 xr.DataArray
对象可以直接用 to_netcdf
等函数保存为文件。
了解基本原理后,我们就可以批量下载数据啦!提供完整的下载脚本以供参考,应该还可以用多线程优化一下。
(另注意降水下载的是mm/6hr,平均到daily后需要转换一下单位)
import os.path
import xarray as xr
import numpy as np
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
ds = xr.open_zarr('gs://weatherbench2/datasets/era5/1959-2023_01_10-wb13-6h-1440x721_with_derived_variables.zarr')
years = np.arange(2000, 2023, 1)
months = np.arange(1, 13, 1)
wb_var_name = {
"t2m" : "2m_temperature",
"msl" : "mean_sea_level_pressure",
"tp" : "total_precipitation_6hr",
"z" : "geopotential",
"u" : "u_component_of_wind",
"v" : "v_component_of_wind",
"q" : "specific_humidity",
"sp" : "surface_pressure",
"ts" : "skin_temperature",
"t" : "temperature",
}
level_required = {
"t2m" : 0,
"msl" : 0,
"tp" : 0,
"z" : [200, 500, 700, 850],
"u" : [200, 500, 700, 850],
"v" : [500, 700, 850],
"q" : [500, 700, 850],
"t" : [500, 700, 850],
"sp" : 0,
"ts" : 0,
}
fdir = "/public/ldata/Data/Reanalysis/ERA5.global.0P25"
def download_daily_era5(year, month, var, level):
if level is None:
file_name = os.path.join(fdir, var, f"daily.{var}.{year}{month:02d}.nc")
else:
file_name = os.path.join(fdir, var, f"daily.{var}{level}.{year}{month:02d}.nc")
os.makedirs(os.path.join(fdir, var), exist_ok=True)
if os.path.isfile(file_name):
print(f"{file_name} already downloaded! skip this request.")
return
print(f"retrieve year: {year}, month: {month}, var: {var}, level: {level}")
month_start = datetime(year, month, 1)
month_end = month_start + relativedelta(months=1) - timedelta(days=1)
if level is None:
ds_sub = ds[wb_var_name[var]].sel(time=slice(month_start, month_end))
ds_sub.load()
ds_daily = ds_sub.resample(time='D').mean()
else:
ds_sub = ds[wb_var_name[var]].sel(time=slice(month_start, month_end)).sel(level=level)
ds_sub.load()
ds_daily = ds_sub.resample(time='D').mean()
ds_daily.to_netcdf(file_name)
print(f"Saved to {file_name}")
del ds_sub, ds_daily
if __name__ == '__main__':
sfc_vars = ['t2m', 'msl', 'tp', 'sp']
for var in sfc_vars:
for year in years:
for month in months:
download_daily_era5(year, month, var, None)
plev_vars = ['z', 'u', 'v', 'q', 't']
for var in plev_vars:
levels = level_required[var]
for year in years:
for month in months:
for level in levels:
download_daily_era5(year, month, var, level)