1. 项目概述:从“数据饥渴”到“精准投喂”
做气象、水文、生态或者农业模型的朋友,对ERA5-Land这个名字一定不陌生。它就像是欧洲中期天气预报中心(ECMWF)为我们这些搞地学研究的人开的一个“数据自助餐厅”,里面摆满了从1950年至今、覆盖全球、时间分辨率最高到小时级、空间分辨率高达9公里的地表再分析数据“硬菜”。温度、降水、土壤湿度、辐射、蒸散发……你能想到的绝大多数地表关键变量,这里几乎都有。但问题来了,这个餐厅的“取餐流程”对新手来说,有点像进了米其林后厨——工具专业、步骤繁多,一不小心就容易“点错菜”或者“下错单”,最后要么等半天没动静,要么下载下来一堆用不了的数据。
我自己在项目初期就踩过不少坑:兴冲冲地选了一大片区域和几十个变量,结果API返回一个错误说请求超载;或者好不容易下载下来一个几十G的NetCDF文件,用Panoply打开一看,时间维度是乱的,还得自己写脚本重排。更常见的是,面对CDS(气候变化数据存储)网站上那密密麻麻的参数列表和复杂的检索语法,感觉无从下手。所以,今天我就结合自己多次“实战”的经验,抛开那些官方的、冗长的教程,直接给你梳理一套从零开始、高效下载ERA5-Land数据的“保姆级”操作流。我们的目标很明确:让你用最少的步骤,拿到最干净、可直接用于分析的数据。
2. 核心需求解析:你到底需要什么样的数据?
在动手敲代码之前,花十分钟想清楚你的需求,能省下后面十个小时的调试和数据处理时间。ERA5-Land数据体量巨大,盲目下载只会带来存储灾难和时间浪费。
2.1 明确时空范围和变量
这是最关键的一步。你需要问自己四个问题:
- 时间范围:你需要哪一段时期的数据?是某个具体的年份,还是连续的多年序列?时间分辨率要多大?是逐小时、逐日还是逐月平均?对于长期趋势分析,月平均数据通常就够了,文件量会小很多;如果研究日变化或极端事件,就必须用小时数据。
- 空间范围:你的研究区在哪里?是一个点(如某个气象站)、一个区域(如某个流域),还是全球?ERA5-Land采用规则的经纬度网格(0.1° x 0.1°,约9公里),你需要用经纬度边界(North, West, South, East)来框定它。注意:这里的“西”和“东”是经度,西经为负,东经为正;“北”和“南”是纬度,北纬为正,南纬为负。例如,中国的范围大致是
[55, 70, 15, 140](北纬55度到15度,东经70度到140度)。建议先用GIS软件或在线地图确认一下边界,避免下错。 - 所需变量:ERA5-Land有超过50个变量。你真正需要的是哪几个?去CDS的 ERA5-Land数据目录 仔细查看变量列表和单位。常见的比如:
2m_temperature:2米高度气温。total_precipitation:总降水量(注意是累积量,小时数据是前一小时内的累积)。surface_solar_radiation_downwards:地表太阳辐射下行。volumetric_soil_water_layer_1:第一层(0-7cm)土壤体积含水量。evaporation_from_vegetation_transpiration:植被蒸腾。
- 数据格式:通常我们选择NetCDF格式,这是地球科学领域的标准格式,可以被绝大多数软件(如Python的xarray, NCL, Panoply, ArcGIS)直接读取。
注意:ERA5-Land的数据有“再分析”性质,它是利用模型同化了大量观测数据得到的,在空间连续性和物理一致性上非常出色,但并非直接的站点观测。在站点稀疏的地区,其精度需要谨慎评估。
2.2 选择下载工具与策略
主要有三种方式,各有优劣:
- CDS Web API(推荐):这是最强大、最自动化的方式。通过Python脚本调用,可以提交任务到后台排队,完成后自动下载。适合批量、定期下载大量数据。你需要注册CDS账号并配置API密钥。
- CDS网页界面手动下载:适合一次性、小范围、少量数据的下载。在网站上通过点选方式设置参数,然后提交请求。对于新手理解参数含义很有帮助,但不适合自动化。
- 第三方工具或镜像:有些科研机构或数据平台可能会提供ERA5-Land的镜像或简化下载工具,但时效性和完整性可能无法保证,且可能涉及版权和数据政策问题,不推荐作为主要渠道。
我们的策略:对于严肃的科研或业务工作,强烈建议掌握CDS API的方式。它虽然前期有一点学习成本,但一旦掌握,后续的数据获取效率是碾压式的。下面我们就重点攻克这种方法。
3. 环境准备与CDS API配置
工欲善其事,必先利其器。在开始写下载脚本前,我们需要把环境搭好。
3.1 注册CDS账号并获取API密钥
- 访问 CDS注册页面 并完成注册。
- 登录后,进入 您的用户页面 ,找到“API密钥”部分。
- 你会看到两行字符串:
URL和Key。把它们记录下来。
3.2 本地配置API密钥
为了让你的Python脚本能通过CDS认证,需要将密钥保存在本地一个配置文件中。
在Linux/macOS系统上:
# 在终端中执行 echo "url: https://cds.climate.copernicus.eu/api/v2 key: <你的UID>:<你的API密钥>" > ~/.cdsapirc请将<你的UID>和<你的API密钥>替换为你网页上看到的实际内容。UID是冒号前的那串数字。
在Windows系统上:
- 在文件资源管理器的地址栏输入
%USERPROFILE%并回车,进入你的用户目录。 - 新建一个名为
.cdsapirc的文本文件(注意前面有个点)。 - 用记事本打开,写入以下内容:
url: https://cds.climate.copernicus.eu/api/v2 key: <你的UID>:<你的API密钥> - 保存文件。确保文件名是
.cdsapirc,而不是.cdsapirc.txt。你可能需要在“查看”选项中勾选“文件扩展名”来确认。
3.3 安装必要的Python库
打开你的命令行(终端或Anaconda Prompt),创建一个新的虚拟环境(可选但推荐),然后安装核心库:
# 创建并激活虚拟环境(以conda为例) conda create -n era5_download python=3.9 conda activate era5_download # 安装CDS API客户端和数据处理库 pip install cdsapi pip install xarray netCDF4cdsapi是与CDS服务器通信的核心库。xarray和netCDF4则是后续读取和处理NetCDF数据文件的利器。
4. 核心下载脚本编写与参数详解
配置好环境后,我们就可以动手编写下载脚本了。我将用一个具体的例子,带你一步步走通,并解释每一个参数的含义。
4.1 基础下载脚本框架
假设我们的需求是:下载中国区域2022年全年的逐日2米气温和总降水量数据。
创建一个Python脚本,例如download_era5_land.py,写入以下代码:
import cdsapi import os # 初始化CDS客户端 c = cdsapi.Client() # 定义你的请求参数 request = { 'product_type': 'reanalysis', 'variable': [ '2m_temperature', 'total_precipitation', ], 'year': '2022', 'month': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'], 'day': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31'], 'time': [ '00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00', ], 'area': [55, 70, 15, 140], # 北,西,南,东 'format': 'netcdf', } # 指定输出文件名 output_file = 'era5_land_china_2022_daily.nc' # 提交下载请求 print(f"正在提交请求,下载数据到: {output_file}") c.retrieve('reanalysis-era5-land', request, output_file) print("下载任务已提交,请等待CDS处理并传输数据。")参数逐行解析:
'product_type': 'reanalysis':固定为reanalysis,表示再分析产品。'variable':列表形式,填写你需要的一个或多个变量名。变量名必须与CDS目录中的完全一致。'year','month','day','time':定义时间维度。注意:'time'参数定义了一天中的哪些小时。即使你想要日平均数据,CDS API也不直接提供“日平均”这个选项。你需要下载所有小时数据(00:00到23:00),然后自己用xarray做时间平均。这是新手常踩的坑。上面脚本下载的就是所有小时数据。'area':[北纬, 西经, 南纬, 东经]。这是定义空间范围最常用的方式。CDS会自动裁剪出这个矩形区域内的数据。'format': 'netcdf':指定输出格式为NetCDF。
运行这个脚本,它会将任务提交到CDS队列。根据数据量大小(本例中范围大、时间长、变量多、时间分辨率高),任务可能需要排队几分钟到几小时。完成后,数据会自动下载到你脚本所在的目录,名为era5_land_china_2022_daily.nc。
4.2 进阶技巧:分块下载与后处理
直接下载全年全球小时数据,文件可能高达数百GB,容易失败且难以处理。更稳健的策略是分而治之。
策略一:按时间分块(推荐)一次只下载一个月或一个季度的数据。可以写一个循环:
years = ['2022'] months = ['01', '02', '03'] # 示例:只下前三个月 for year in years: for month in months: request['year'] = year request['month'] = month # 可以只下载特定几天,减少单次请求量 request['day'] = ['01', '02', '03', '04', '05'] request['time'] = ['00:00', '06:00', '12:00', '18:00'] # 甚至可以先下4个时次试试 output_file = f'era5_land_china_{year}_{month}.nc' c.retrieve('reanalysis-era5-land', request, output_file) print(f"{year}-{month} 数据下载完成。")策略二:按变量分块如果你需要很多变量,但时间范围不长,可以一次只下一个变量,避免单个请求过于复杂。
策略三:下载后合并使用xarray可以轻松合并按时间分块的数据:
import xarray as xr import glob # 找到所有分块文件 file_list = sorted(glob.glob('era5_land_china_2022_*.nc')) # 用xarray打开并沿时间维度合并 ds = xr.open_mfdataset(file_list, combine='by_coords', parallel=True) # 计算日平均(如果需要) ds_daily = ds.resample(time='1D').mean() # 保存为新的文件 ds_daily.to_netcdf('era5_land_china_2022_daily_mean.nc') ds.close()实操心得:在提交大型请求前,务必先用极小的范围(如一个点、一天、一个变量)测试你的脚本。确保参数无误、网络通畅、API密钥有效。测试成功后再逐步放大请求规模。CDS对单个请求的数据量有限制,分块下载是绕过限制、提高成功率的最佳实践。
5. 数据读取、初步检查与常见单位转换
数据下载到手后,别急着往模型里灌。先做一次“体检”。
5.1 使用Xarray快速查看数据
import xarray as xr ds = xr.open_dataset('era5_land_china_2022_daily_mean.nc') print(ds)这会打印出数据集的摘要信息,包括维度(经度、纬度、时间)、坐标、数据变量及其属性。重点关注:
- 变量单位:例如,
2m_temperature的单位通常是K(开尔文),total_precipitation是m(米)。 - 时间坐标:检查时间序列是否连续,有没有重复或缺失。
- 空间范围:检查经纬度边界是否符合你的预期。
5.2 常用单位转换
ERA5-Land数据使用的单位通常是国际单位制(SI),但我们在分析时可能需要转换:
- 温度:从开尔文(K)转换到摄氏度(°C)。
temperature_c = ds['t2m'] - 273.15 - 降水:从米(m)转换到毫米(mm)。
precipitation_mm = ds['tp'] * 1000。特别注意:对于小时数据,tp是累积量;对于日数据,如果你是对小时数据做平均,得到的是平均累积率,意义可能不对。通常做法是对小时累积量进行日求和:daily_precip = ds['tp'].resample(time='1D').sum() * 1000。 - 辐射:地表净辐射通常已是
W m**-2,可以直接使用。
5.3 可视化快速检查
用几行代码做个简单的空间分布图,直观检查数据是否异常:
import matplotlib.pyplot as plt # 选择某个时间点绘制气温空间图 ds['t2m'].isel(time=0).plot() plt.title('2m Temperature - First Time Step') plt.show() # 绘制某个站点(经纬度点)的时间序列 # 使用最近邻查找,假设站点在(116.4, 39.9) - 北京附近 lon = 116.4 lat = 39.9 # xarray的sel方法支持最近邻查找 ts_temperature = ds['t2m'].sel(longitude=lon, latitude=lat, method='nearest') ts_temperature.plot() plt.title(f'Temperature Time Series at ({lon}, {lat})') plt.show()6. 常见问题与排查技巧实录
在实际操作中,你几乎一定会遇到下面这些问题。我把我的踩坑记录和解决方案整理如下:
6.1 错误:“Invalid request: Request too large”
问题描述:提交请求后,CDS返回错误,提示请求太大。
原因与解决:这是CDS对单次请求数据量的保护机制。
- 最有效的方法:采用前面提到的“分块下载”策略。将长时间序列按年、按月甚至按旬拆分。
- 减少空间范围:如果不是必需,尽量不要请求全球数据。
- 降低时间分辨率:如果研究允许,先尝试下载逐3小时或逐6小时的数据,而不是逐小时数据。
- 减少变量:只选择最核心的变量。
6.2 错误:“Authentication failed”
问题描述:运行脚本时报错,提示认证失败。
原因与解决:API密钥配置有问题。
- 检查
.cdsapirc文件:确保文件在正确的位置(用户主目录),且内容格式正确,UID和Key没有多余空格或换行。 - 验证密钥有效性:可以登录CDS网站,在用户页面查看API密钥状态是否正常。
- 环境变量:在某些服务器环境下,也可以通过设置环境变量
CDSAPI_URL和CDSAPI_KEY来配置,这比文件优先级更高。检查是否有冲突。
6.3 下载任务长时间处于“排队”或“运行”状态
问题描述:任务提交后,在CDS网页的“任务”列表里一直不完成。
原因与解决:
- 正常排队:CDS是一个全球共享资源,高峰时段排队几小时很正常。耐心等待即可。
- 检查任务详情:点击任务ID,查看是否有错误信息。有时是参数设置问题导致任务内部失败。
- 任务类型:“再分析”数据(ERA5-Land)是预先计算好的,通常比需要实时计算的“预报”产品快。
- 网络问题:偶尔会出现数据传输卡住。可以尝试取消任务,稍后重新提交。
6.4 数据下载中断或文件损坏
问题描述:下载过程中网络中断,导致文件不完整,无法用xarray打开。
原因与解决:
- 使用CDS API的断点续传:
cdsapi库本身不支持断点续传。如果中断,通常需要重新提交请求。 - 手动处理:对于非常大的文件,可以考虑使用
wget或curl命令来下载CDS提供的临时链接(在任务完成后可见),这些工具支持断点续传。但API方式更规范。 - 预防措施:分块下载小文件,是避免因单个大文件下载失败而前功尽弃的最好方法。
6.5 数据时间坐标混乱或存在重复
问题描述:用xarray打开多个文件合并后,发现时间坐标不是单调递增的,或者有重复。
原因与解决:
- 时区问题:ERA5-Land使用UTC时间。如果你的本地环境或分析脚本没有正确处理时区,可能会导致显示问题。确保所有时间操作都在UTC下进行。
- 合并操作不当:使用
xr.open_mfdataset时,务必指定combine='by_coords',让xarray根据坐标自动对齐和合并。如果文件间有时间重叠,合并时可能会出错,需要先检查各个文件的时间范围。 - 数据本身问题:极少数情况下,CDS的数据文件可能有误。可以对比不同来源或不同下载时间的数据。
6.6 内存不足处理大文件
问题描述:使用xr.open_dataset()直接打开几十GB的NetCDF文件时,内存爆满。
原因与解决:不要一次性将数据读入内存。
- 分块读取与延迟计算:
xarray配合dask可以完美处理这个问题。在打开文件时指定chunks参数:
这样数据会以“块”的形式懒加载,只有在实际计算时才会读入相应的块。ds = xr.open_dataset('large_file.nc', chunks={'time': 100, 'latitude': 100, 'longitude': 100}) - 选择性读取:如果只需要特定区域或时间,使用
sel或isel进行索引切片,再加载到内存:subset = ds.sel(latitude=slice(20, 50), longitude=slice(100, 130), time=slice('2022-06-01', '2022-08-31')) # 此时subset才是一个实际加载了数据的内存对象 - 使用
compute():对于基于dask的延迟计算对象,记得在需要结果时调用.compute()。
掌握以上这些内容,你基本上就能独立、高效地获取和处理ERA5-Land数据了。整个过程的核心思路就是:明确需求 -> 分块请求 -> 后处理合并 -> 检查验证。这套方法不仅适用于ERA5-Land,对于其他类似的通过API提供的大型气象海洋数据集(如ERA5、CAMS等)也同样有效。数据下载只是第一步,但走稳这一步,后续的分析之路才会更顺畅。