ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ERA5小时数据批量下载与cdo高效处理实战指南

ERA5小时数据批量下载与cdo高效处理实战指南 1. 项目概述为什么ERA5小时级数据值得花时间批量下载与处理做气象、气候、能源或环境建模的朋友大概率都绕不开ERA5——这是欧洲中期天气预报中心ECMWF发布的全球再分析数据集空间分辨率0.25°×0.25°时间覆盖1940年至今每小时一帧变量超50个温度、湿度、风速、辐射、降水、位势高度……。它不是卫星原始观测也不是模式实时预报而是把海量地面站、探空、卫星、飞机报等异构观测数据用四维变分同化方法“反演”进高分辨率数值模型里生成的一致、连续、物理自洽的全球大气状态场。简单说它是目前最权威、最完整、最易获取的“地球历史天气录像带”。但问题来了——你真去ECMWF官网点选下载会发现单次请求最多只能下1个月、1个变量、1个层级的数据想下2015–2023年全球地表气温逐小时数据得手动点选8年×12月×24小时2304次还要反复填表单、等邮件确认、手动解压、重命名、拼接nc文件……这根本不是科研是体力劳动。更糟的是官方Web APICDS API虽支持脚本调用但默认限流严格每分钟最多3个请求、配额有限免费用户每月50GB、且对并发和错误重试极不友好。我去年帮一个风电功率预测团队搭数据流水线光调试下载逻辑就花了3天中间因API返回空文件、token过期、服务器503、nc文件header损坏等问题反复重跑17次。这时候“ERA5 hourly data批量下载与cdo处理”就不是锦上添花而是刚需。它本质是一套可复用、可监控、可回溯的数据工程闭环从认证→参数化请求→断点续传→校验解压→格式统一→变量裁剪→时间聚合→空间插值→元数据标准化全部用命令行脚本驱动。而cdoClimate Data Operators就是这个闭环里的“瑞士军刀”——它不依赖Python环境内存占用低支持流式处理单条命令就能完成nc文件的合并、筛选、计算、重采样、单位转换。比如cdo mergetime *.nc -O merged.nc5秒合并100个文件cdo sellonlatbox,-10,30,20,50 in.nc out_subset.nc一行切出中国区域cdo timmean -tstep,24 in.nc daily_mean.nc直接算日均值——这些操作若用xarray写Python脚本代码量翻3倍运行时间多2倍还容易因dask调度失败中断。所以这篇不是教你怎么点鼠标而是带你亲手搭一条“ERA5小时数据自动流水线”。它不依赖任何图形界面全程Linux终端操作所有脚本可直接复制粘贴运行每个参数都有物理意义解释比如为什么time要拆成year/month为什么grid_mapping必须保留所有坑我都踩过——包括CDS API返回的nc文件缺time_bnds、cdo在Ubuntu 20.04上因netCDF库版本冲突报错、Windows子系统WSL2中curl证书验证失败……这些细节文档不会写但实操时能让你少熬3个通宵。适合谁看气象/水文/能源领域研究生正为毕业论文准备长序列驱动数据环境咨询公司工程师需定期更新城市热岛分析的历史基线风光功率预测算法工程师要构建过去5年逐小时NWP偏差数据库地理信息系统GIS从业者需将ERA5格点数据转为GeoTIFF供ArcGIS调用。只要你需要稳定、可重复、可审计地获取ERA5小时级数据这篇就是你的第一份工程手册。2. 整体架构设计为什么选择CDS API Bash cdo组合而非Python全栈很多人第一反应是“Python不是有cdsapi、xarray、netCDF4吗写个for循环不就完了”——理论上可行但实操中会撞上三堵墙稳定性墙、资源墙、可维护性墙。我用Python全栈方案跑过2TB ERA5数据1979–2022全球2m气温结果如下维度Python方案cdsapi xarrayBash CDS API cdo方案单次下载成功率68%API超时/连接重置/JSON解析失败频发99.2%curl -f retry机制 文件大小校验内存峰值占用12.4 GBxarray读取100个nc文件时dask自动加载全部chunk186 MBcdo流式处理内存只存当前块100GB数据处理耗时47分钟Python序列化GCI/O阻塞11分钟cdo并行编译底层netCDF-C优化故障定位难度需查日志、debug变量、重放API请求错误直接输出curl/cdo命令行5秒定位是网络还是文件问题跨平台兼容性Windows需conda环境macOS需brew install hdf5WSL2/Ubuntu/CentOS原生支持无依赖冲突所以最终架构定为三层流水线第一层认证与请求层Bash curl不用Python的cdsapi库改用ECMWF官方推荐的curl方式调用CDS API。原因很实在cdsapi本质是封装curl但封装后丢失了对HTTP状态码、重试策略、响应头的精细控制。而我们用curl -X POST -H Authorization: Bearer ${TOKEN} --data-binary request.json https://cds.climate.copernicus.eu/api/v2/resources/...可以精确捕获HTTP 429 Too Many Requests并sleep 60秒可以检查Content-Length是否为0空响应可以保存原始response body用于debug。更重要的是——所有操作都在shell里没有Python环境污染风险。第二层数据质检与预处理层Bash md5sum cdo下载完的.nc文件不是直接扔进分析流程。先做三件事①md5sum校验ECMWF提供每个文件的MD5哈希下载后比对防传输损坏②cdo -s infov file.nc快速读取文件头验证time维度长度是否匹配请求比如请求30天应有720个时间步少于718个即为残缺③cdo sinfov file.nc \| grep -E lon|lat|time提取坐标范围确保没下错区域。这三步加起来不到0.5秒/文件却能避免后续数小时的无效计算。第三层核心处理层cdo单命令链这才是cdo的真正价值区。它不像Python需要写循环读写而是把nc文件当“流”处理输入是文件路径输出是新文件中间所有操作merge、sellatlon、timmean、remapbil都在内存buffer里完成。比如处理中国区域逐小时2m气温典型命令链是cdo -O -z zip_3 merge $(ls era5_2mtemp_2020*.nc) temp_merged.nc \ cdo -O sellonlatbox,-10,130,0,60 temp_merged.nc temp_china.nc \ cdo -O timmean -tstep,24 temp_china.nc temp_china_daily.nc \ cdo -O setgridfile,china_grid.txt temp_china_daily.nc temp_china_daily_regrid.nc注意-O强制覆盖输出-z zip_3用zlib level 3压缩节省50%空间-tstep,24指定按24步聚合即日平均setgridfile用外部网格定义文件实现自定义重采样——这些参数背后都有物理约束比如timmean必须保证输入文件时间轴严格连续否则cdo报错sellonlatbox的经纬度范围必须与原始网格对齐否则插值失真这些细节我会在后续章节展开。选择这套组合本质是用最简工具链解决最痛问题下载要稳处理要快维护要省。Python适合做复杂统计建模但不适合做数据搬运工而cdo就是专为搬运设计的重型卡车——它不炫技但拉得动、跑得稳、修得快。3. 核心细节解析CDS API认证、请求构造与下载脚本实操3.1 获取并安全存储CDS API密钥ECMWF要求所有CDS API调用必须携带Bearer Token该Token由你的CDS账户生成形如xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。获取路径登录 Climate Data Store → 右上角头像 → “User Profile” → “API key” → 点击“Show API key”。关键警告绝对不要把Token硬编码在脚本里我见过太多人把Token传到GitHub导致账号被盗ECMWF会立即封禁该Token并追溯所有下载记录。正确做法是创建凭证文件~/.cdsapircLinux/macOS或%USERPROFILE%\cdsapircWindows内容为url: https://cds.climate.copernicus.eu/api/v2 key: 12345:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx其中12345是你的UID在API key页面URL中可见如https://cds.climate.copernicus.eu/user/12345冒号后是Token。然后设置权限chmod 600 ~/.cdsapirc # Linux/macOS icacls %USERPROFILE%\cdsapirc /inheritance:r /grant:r %USERNAME%:F # Windows这样curl就能自动读取curl --config ~/.cdsapirc ...。如果必须用环境变量如CI/CD场景则用export CDSAPI_KEY12345:xxx并在脚本开头加if [ -z $CDSAPI_KEY ]; then echo ERROR: CDSAPI_KEY not set; exit 1; fi。3.2 构造符合ERA5规范的JSON请求体ERA5小时数据分多个数据集dataset最常用的是reanalysis-era5-single-levels近地面变量和reanalysis-era5-pressure-levels气压层变量。请求体必须严格遵循schema漏掉一个字段或类型错误都会返回400 Bad Request。以下载2020年全球2m气温为例request.json内容如下{ format: netcdf, product_type: reanalysis, variable: [2m_temperature], year: [2020], 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: [90, -180, -90, 180], grid: [0.25, 0.25] }逐字段说明format: netcdf必须小写不能写NetCDF或nc否则返回400area: [N, W, S, E]北极在前南极在后西经为负东经为正。[90,-180,-90,180]即全球[50,70,15,140]即东亚注意顺序是北纬、西经、南纬、东经grid: [0.25, 0.25]明确指定分辨率否则默认0.5°且无法与0.25°数据混用day数组必须包含所有日期即使某月只有30天也要写31ERA5会自动忽略不存在的日期time必须写24个字符串不能写[00:00/23:00]否则报错。提示area和grid看似可选但强烈建议显式声明。因为ERA5不同变量默认网格不同如辐射变量用0.5°温度用0.25°不声明会导致下载文件坐标系混乱cdo处理时报grid mismatch。3.3 批量下载脚本断点续传与智能重试以下是一个生产级下载脚本download_era5.sh支持年份/变量/区域参数化核心逻辑是① 检查目标目录是否存在已下载文件跳过已存在项② 对每个请求生成唯一ID基于yearvararea哈希避免重复提交③ curl失败时根据HTTP状态码采取不同策略429限流sleep 60秒503服务忙sleep 120秒其他错误重试3次④ 下载后立即校验文件大小ERA5每小时文件约12MB小于10MB即为失败。#!/bin/bash # download_era5.sh - 支持断点续传的ERA5批量下载器 YEAR${1:-2020} # 第一个参数年份默认2020 VAR${2:-2m_temperature} # 第二个参数变量名默认2m_temperature AREA${3:-90/-180/-90/180} # 第三个参数区域格式N/W/S/E # 创建下载目录 OUTDIRera5_${VAR}_${YEAR} mkdir -p $OUTDIR # 生成请求JSON此处简化实际用jq动态生成 cat request.json EOF { format: netcdf, product_type: reanalysis, variable: [${VAR}], year: [${YEAR}], 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: [${AREA}], grid: [0.25, 0.25] } EOF # 提交请求并获取任务ID TASK_ID$(curl -s --config ~/.cdsapirc -X POST \ -H Content-Type: application/json \ --data-binary request.json \ https://cds.climate.copernicus.eu/api/v2/resources/reanalysis-era5-single-levels | \ jq -r .request_id) if [ $TASK_ID null ] || [ -z $TASK_ID ]; then echo ERROR: Failed to submit request exit 1 fi echo Task submitted: $TASK_ID # 轮询任务状态直到完成或失败 MAX_RETRY60 RETRY0 while [ $RETRY -lt $MAX_RETRY ]; do STATUS$(curl -s --config ~/.cdsapirc \ https://cds.climate.copernicus.eu/api/v2/resources/reanalysis-era5-single-levels/$TASK_ID | \ jq -r .state) case $STATUS in completed) echo Download completed break ;; failed) echo Task failed: $(curl -s --config ~/.cdsapirc \ https://cds.climate.copernicus.eu/api/v2/resources/reanalysis-era5-single-levels/$TASK_ID | \ jq -r .error.message) exit 1 ;; queued|running) echo Status: $STATUS, waiting... sleep 30 ;; *) echo Unknown status: $STATUS sleep 30 ;; esac RETRY$((RETRY 1)) done if [ $RETRY -eq $MAX_RETRY ]; then echo ERROR: Task timeout after $MAX_RETRY attempts exit 1 fi # 下载文件CDS API返回的download_url需用curl -L重定向 DOWNLOAD_URL$(curl -s --config ~/.cdsapirc \ https://cds.climate.copernicus.eu/api/v2/resources/reanalysis-era5-single-levels/$TASK_ID | \ jq -r .location) if [ $DOWNLOAD_URL null ]; then echo ERROR: No download URL found exit 1 fi # 实际下载带进度条和校验 curl -L -# --config ~/.cdsapirc $DOWNLOAD_URL -o ${OUTDIR}/era5_${VAR}_${YEAR}.nc || { echo Download failed; exit 1; } FILE_SIZE$(stat -c%s ${OUTDIR}/era5_${VAR}_${YEAR}.nc 2/dev/null || stat -f%z ${OUTDIR}/era5_${VAR}_${YEAR}.nc 2/dev/null) if [ $FILE_SIZE -lt 10000000 ]; then # 小于10MB视为失败 echo ERROR: Downloaded file too small ($FILE_SIZE bytes) rm ${OUTDIR}/era5_${VAR}_${YEAR}.nc exit 1 fi echo Download success: ${OUTDIR}/era5_${VAR}_${YEAR}.nc注意此脚本假设你已安装jqJSON处理器和curl。Ubuntu下sudo apt install curl jqmacOS下brew install curl jq。Windows用户请用WSL2原生PowerShell对JSON解析支持极差。3.4 下载后质检三步验证法确保数据可用下载完成不等于数据可用。我曾收到一个“成功下载”的nc文件用cdo info看时间轴正常但用ncks -v t2m file.nc -O test.nc抽变量时崩溃——原因是ECMWF在2021年某次更新中悄悄把time_bnds变量的units从hours since 1900-01-01改成days since 1900-01-01导致xarray解析失败。因此必须做三步验证第一步基础结构验证cdo -s infov ${OUTDIR}/era5_${VAR}_${YEAR}.nc | head -20检查输出中是否有time、latitude、longitude维度以及time的size是否等于该年小时数2020年闰年366×248784。若size为0或远小于8784说明下载不全。第二步坐标一致性验证cdo -s griddes ${OUTDIR}/era5_${VAR}_${YEAR}.nc输出应为gridtype lonlat gridsize 1440 xsize 1440 ysize 721 xname longitude xlongname longitude xunits degrees_east yname latitude ylongname latitude yunits degrees_north关键看xsize1440360°/0.25°1440、ysize721180°/0.25°1721若ysize720说明缺少赤道线常见于旧版数据需用cdo -P 4 setgrid,global_025deg ${file} ${out}修复。第三步变量完整性验证cdo -s showvar ${OUTDIR}/era5_${VAR}_${YEAR}.nc确认输出包含请求的变量名如t2m且无missing_value异常。若出现***或NaN占比过高说明数据质量有问题需重新下载。这三步加起来不到3秒却能避免后续数小时的无效计算。记住宁可多花3秒验证也不愿多花3小时debug。4. cdo核心处理从原始nc到分析就绪数据的7个关键操作4.1 合并分散文件用mergetime替代cat的物理意义ERA5小时数据默认按月分卷下载如era5_t2m_202001.nc,era5_t2m_202002.nc…直接cat *.nc merged.nc会破坏netCDF结构——因为nc文件不是纯二进制流它有全局属性、维度定义、变量属性等元数据头。cat会把第二个文件的头追加到第一个文件末尾导致读取时维度错乱。正确方法是cdo mergetime *.nc merged.nc。其原理是cdo先读取所有输入文件的time维度按时间戳升序排序然后创建新的time维度长度总小时数再将各文件对应时间步的数据块按序写入新文件。过程中自动处理时间轴单位统一自动转换hours since或days sincetime_bnds变量同步更新每个时间步的起止时间全局属性继承保留ConventionsCF-1.6等关键标识坐标变量去重longitude、latitude只保留一份。实测对比100个12MB文件共1.2GBcat耗时2.1秒但文件不可读cdo mergetime耗时8.7秒但输出完美nc文件。多花6秒换来100%可靠性。提示若文件时间轴不连续如缺2020-02-29mergetime会报错time axis not monotonic。此时先用cdo seltimestep,1/8784 file.nc fixed.nc强制截取有效时间步再合并。4.2 空间裁剪sellonlatbox的边界陷阱与地理精度cdo sellonlatbox,W/E/S/N in.nc out.nc是最常用的空间裁剪命令但W/E/S/N的取值有严格地理约定经度W/E西经为负东经为正且W必须小于E如中国区域W-10,E130纬度S/N南纬为负北纬为正且S必须小于N如中国区域S0,N60关键陷阱ERA5的latitude维度是从北向南递减的90°→-90°而sellonlatbox内部按“南纬/北纬”理解所以S0,N60实际裁出的是赤道到北纬60°完全正确但若误写S60,N0cdo会静默返回空文件。更隐蔽的问题是网格对齐。ERA5的0.25°网格经度从-180°开始每步0.25°即-180.00, -179.75, -179.50, ..., 179.75纬度从90°开始90.00, 89.75, 89.50, ..., -89.75。若你设W100.1,E120.3cdo会自动向下取整到最近网格点W100.00,E120.25导致边界偏移0.1°–0.25°。解决方案是显式指定网格cdo -P 4 sellonlatbox,100.0,120.25,20.0,40.0 in.nc out.nc-P 4启用4线程加速100.0/120.25/20.0/40.0严格对齐原始网格。实测裁剪中国区域73°–135°E, 3°–53°N时用sellonlatbox,73,135,3,53比sellonlatbox,70,140,0,60减少32%数据量且无插值失真。4.3 时间聚合timmean与timselhour的物理约束ERA5小时数据常需转为日均、月均或特定时段均值。cdo timmean是最直接命令但有两个硬约束时间轴必须严格连续若缺1小时timmean会报错time axis has gaps。解决方案是先用cdo setmisstoc,0 in.nc filled.nc填充缺失值填0或用cdo cat in.nc (cdo seltimestep,1/1 in.nc | cdo settaxis,1900-01-01,00:00,1hour)补全时间轴聚合步长必须整除总步长如8784小时2020年可被24整除日均但不能被25整除。cdo timmean -tstep,25 in.nc会失败。更灵活的是timselhour和timselmoncdo timselhour,0,6,12,18 in.nc out_4times.nc抽取每天0/6/12/18时四次数据cdo timselmon,1,2,3,4,5,6 in.nc out_jan_jun.nc抽取1–6月数据cdo timselperiod,day,1,31 in.nc out_day1_31.nc抽取每月1–31日自动跳过不存在日期。这些命令不改变时间轴连续性适合做子集分析。例如风电预测中只需每天13–15时风速用timselhour,13,14,15比timmean更精准。4.4 坐标重映射remapbil与setgrid的精度权衡原始ERA5是规则经纬度网格lonlat但很多模型如WRF、CESM需要高斯网格或自定义投影。cdo remapbil用双线性插值重采样语法为cdo -P 4 remapbil,global_05deg in.nc out_05deg.nc其中global_05deg是预定义网格名cdo内置也可用自定义网格文件china_01deg.txtgridtype lonlat xsize 1200 ysize 600 xvals 70 70.01 70.02 ... 130 yvals 53 52.99 52.98 ... 3remapbil精度高但慢remapnn最近邻快但有锯齿remaplaf面积守恒适合通量变量如降水。选择依据是温度/湿度等标量场 →remapbil风矢量u/v→ 必须用remapbic双线性插值矢量校正否则风向失真降水/辐射等通量 →remaplaf保证积分守恒。实操心得重映射前务必用cdo -s gridarea in.nc area.nc计算原始网格面积再用cdo div area.nc out.nc归一化否则重采样后单位错乱。这是90%新手忽略的致命细节。4.5 单位与变量名标准化setunit与chname的CF合规性ERA5变量名如t2m和单位如K符合CF标准但下游模型可能要求temperature_2m和°C。cdo提供精准修改命令cdo -P 4 setunit,degC -subc,273.15 t2m.nc temp_c.nc # K转°C cdo -P 4 chname,t2m,temperature_2m temp_c.nc final.nc # 重命名变量 cdo -P 4 setattribute,temperature_2mlong_name,2-meter temperature final.nc final_v2.ncsetunit修改units属性subc,273.15对变量值减273.15chname改变量名setattribute加长名称。这些操作不改变数据值只更新元数据确保CF合规性Climate and Forecast Metadata Conventions。很多GIS软件如QGIS依赖long_name和units渲染图例不设则显示为t2m (unknown)。4.6 数据压缩与格式优化-z zip_3与-f nc4的存储效率ERA5原始nc文件未压缩1小时全球数据约12MB。用cdo -z zip_3可压缩至3.5MB压缩率70%且cdo读取时自动解压无性能损失。zip_3是zlib level 3平衡速度与压缩率zip_9压缩率更高但耗时翻倍不推荐。更进一步转为netCDF4格式cdo -f nc4 -z zip_3 copy in.nc out.nc4netCDF4支持分块chunking和Shuffle过滤对大文件随机访问更快。实测10GB文件nc4比nc3读取速度提升40%存储节省15%。但注意旧版GrADS或MATLAB可能不支持nc4需确认下游工具兼容性。4.7 批量处理管道用findxargs构建自动化流水线单个命令易写批量处理才见功力。例如将100个年份文件全部裁剪为中国区域并转°Cfind era5_t2m_* -name *.nc | xargs -I {} bash -c BASE$(basename {} .nc) cdo -P 4 sellonlatbox,73,135,3,53 {} china_${BASE}.nc \ cdo -P 4 setunit,degC -subc,273.15 china_${BASE}.nc china_${BASE}_c.nc \ rm {} china_${BASE}.nc xargs -I {}将每个文件路径代入命令bash -c启动子shell避免变量冲突。加上-P 4启用4进程并行100个文件处理时间从32分钟降至9分钟。这是真正落地的“批量”——不是概念是秒级响应的生产力。5. 常见问题与排查技巧实录那些文档不会写的实战经验5.1 CDS API返回空文件或4045种
返回列表