当前位置:首页>python>python下载CAMS全球大气成分预报数据

python下载CAMS全球大气成分预报数据

  • 2026-10-11 08:04:06
python下载CAMS全球大气成分预报数据

数据概述

CAMS(Copernicus Atmosphere Monitoring Service)全球近实时大气成分预报数据由欧洲中期天气预报中心(ECMWF)代表欧盟运营,是哥白尼计划的核心产品之一。该数据提供全球范围内主要大气污染物、温室气体和气溶胶的每日预报。

  • 数据名称:CAMS global atmospheric composition forecasts

  • 提供机构:ECMWF

  • 官方页面:https://ads.atmosphere.copernicus.eu

  • 获取方式:FTP近实时推送(保留3天)+ ADS归档下载

  • 更新频率:每日两次(00UTC和12UTC)

  • 数据格式:GRIB2

预报系统介绍

CAMS基于ECMWF的集成预报系统(IFS Cycle 48r1),耦合大气化学和气溶胶模块:

  • 气象核心:IFS,T511谱截断(~40km)

  • 化学模块:C-IFS,CB05机制 + 线性化臭氧化学

  • 气溶胶:5类(海盐、沙尘、有机碳、黑碳、硫酸盐),每类3个粒径段

  • 排放源:CAMS-GLOB-ANT v5.3(人为)+ GFAS(野火实时)+ 自然源

  • 同化:4D-Var同化GOME-2、TROPOMI、MODIS、IASI等卫星观测

  • 垂直层:137层模式面 + 20层等压面(1000-10hPa)

  • 预报时长:120小时(5天)

地面变量清单

变量名
缩写
单位
说明
2米温度
2t
K
2米露点温度
2d
K
10米U/V风
10u/10v
m/s
100米U/V风
100u/100v
m/s
平均海平面气压
msl
Pa
地表气压
sp
Pa
总降水量
tp
m
对流+大尺度
大尺度/对流降水
lsp/cp
m
降雪量/雪深
sf/sd
m/m
总/低/中/高云量
tcc/lcc/mcc/hcc
0-1
总柱水汽/云水
tcwv/tcw
kg/m²
能见度
vis
m
地表/净/晴天太阳辐射
ssrd/ssr/ssrc
J/m²
累积量
直射太阳辐射
fdir
J/m²
海表/地表温度
sst/skt
K
土壤温度/湿度(0-7cm)
stl1/swvl1
K / m³/m³
对流有效位能/抑制
cape/cin
J/kg
紫外线指数
uvi
-

大气化学变量

变量名
缩写
单位
说明
细颗粒物PM2.5
pm2p5
kg/m³
粗颗粒物PM10
pm10
kg/m³
臭氧
o3
kg/kg
二氧化氮
no2
kg/kg
一氧化碳
co
kg/kg
二氧化硫
so2
kg/kg
甲醛
hcho
kg/kg
硝酸
hno3
kg/kg
过氧乙酰硝酸酯
pan
kg/kg
羟基自由基
oh
kg/kg

气溶胶变量

分粒径段(细/中/粗):

类型
细模态(μm)
中模态(μm)
粗模态(μm)
海盐
0.03-0.5
0.5-5
5-20
沙尘
0.03-0.55
0.55-9
9-20
有机碳
亲水
疏水
-
黑碳
亲水
疏水
-
硫酸盐
-
-
-

气溶胶光学厚度(550nm):总AOD、沙尘AOD、海盐AOD、有机碳AOD、黑碳AOD、硫酸盐AOD

等压面层变量

20层:1000, 950, 925, 900, 850, 800, 700, 600, 500, 400, 300, 250, 200, 150, 100, 70, 50, 30, 20, 10 hPa

变量
缩写
单位
比湿
q
kg/kg
相对湿度
r
%
温度
t
K
U/V风
u/v
m/s
位势高度
z
m²/s²
臭氧
o3
kg/kg
CO/NO₂/SO₂
co/no2/so2
kg/kg

模式层变量

量
缩写
单位
U/V风
u/v
m/s

MODEL LEVEL 137

01

账号注册

  1. 访问 ECMWF 支持门户:https://support.ecmwf.int

  2. 注册账号,提交 CAMS Global Near-Real-Time Data 访问申请

  3. 审批通过后收到邮件,包含:

    • 服务器:aux.ecmwf.int

    • 协议:FTP

    • 用户名:系统分配(如 una.x)

    • 密码:系统自动生成

02

环境准备

# 安装lftp(高性能多线程FTP客户端)sudo apt-get install -y lftp# 创建目录结构mkdir -p /home/ubuntu/cams_dl/{test_data,logs}

03

为什么用lftp

  • 支持多线程并发下载(mirror --parallel=8)

  • 自动断点续传

  • 比ftp命令快3-5倍

  • 支持正则过滤

05

下载脚本

#!/usr/bin/env python3"""CAMS数据下载 + 合并GRIB"""import os, sys, subprocess, logging, time, glob, shutilfrom datetime import datetime, timedeltaFTP_HOST = "***"FTP_USER = "***"FTP_PASS = "***"REMOTE_DIR = "/DATA/CAMS_GLOBAL"LOCAL_DIR = "/download"TMP_DIR = os.path.join(LOCAL_DIR, "tmp")SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))LOG_DIR = os.path.join(SCRIPT_DIR, "logs")MAX_RETRY = 3os.makedirs(LOCAL_DIR, exist_ok=True)os.makedirs(LOG_DIR, exist_ok=True)WANTED = [    "aod550", "ssaod550", "duaod550", "bcaod550", "suaod550", "omaod550",    "pm2p5", "pm10",    "2t", "2d", "10u", "10v", "msl", "sp", "tcwv",    "vis", "go3", "co", "so2", "no2", "hcho",]defkeep_file(filename):    ifnot filename.endswith(".grib"):        returnFalse    for w in WANTED:        iff"_{w}."in filename:            returnTrue    returnFalsedefget_logger():    logger = logging.getLogger("cams")    logger.setLevel(logging.INFO)    logger.handlers.clear()    fmt = logging.Formatter("%(asctime)s %(message)s", "%H:%M:%S")    ch = logging.StreamHandler(); ch.setFormatter(fmt); logger.addHandler(ch)    fh = logging.FileHandler(os.path.join(LOG_DIR, f"dl_{datetime.now().strftime('%Y-%m')}.log"))    fh.setFormatter(logging.Formatter("%(asctime)s %(message)s", "%m-%d %H:%M:%S"))    logger.addHandler(fh)    return loggerlogger = get_logger()defdownload_one(batch):    date_part = f"{batch[:4]}-{batch[4:6]}-{batch[6:8]}"    outfile = os.path.join(LOCAL_DIR, f"cams_{date_part}_{batch[8:10]}.grib")    if os.path.exists(outfile) and os.path.getsize(outfile) > 50_000_000:        logger.info(f"[SKIP] {os.path.basename(outfile)}")        returnTrue    tmp_dir = os.path.join(TMP_DIR, batch)    os.makedirs(tmp_dir, exist_ok=True)    t0 = time.time()    logger.info(f"[START] {batch}")    for attempt inrange(1, MAX_RETRY + 1):        lftp_cmds = f"""open {FTP_HOST}user {FTP_USER}{FTP_PASS}set ftp:ssl-allow nolcd {tmp_dir}cd {REMOTE_DIR}/{batch}mget *.gribbye"""        try:            r = subprocess.run(                ["lftp"],                input=lftp_cmds,                capture_output=True,                text=True,                timeout=7200            )            all_files = glob.glob(os.path.join(tmp_dir, "*.grib"))            if r.returncode == 0and all_files:                keep = sorted([f for f in all_files if keep_file(os.path.basename(f))])                removed = len(all_files) - len(keep)                for f in all_files:                    if f notin keep:                        os.remove(f)                logger.info(f"[FILTER] keep={len(keep)} del={removed}")                withopen(outfile, 'wb') as out:                    for f in keep:                        withopen(f, 'rb') as inp:                            out.write(inp.read())                shutil.rmtree(tmp_dir, ignore_errors=True)                elapsed = int(time.time() - t0)                size_mb = os.path.getsize(outfile) / 1_048_576                logger.info(f"[OK] {os.path.basename(outfile)}{size_mb:.0f}MB {elapsed}s")                returnTrue            if attempt < MAX_RETRY:                logger.warning(f"[RETRY] {batch}{attempt}/{MAX_RETRY}")                time.sleep(15)        except subprocess.TimeoutExpired:            logger.warning(f"[TIMEOUT] {batch}")        except Exception as e:            logger.error(f"[ERR] {batch}: {e}")    shutil.rmtree(tmp_dir, ignore_errors=True)    logger.error(f"[FAIL] {batch}")    returnFalseif __name__ == "__main__":    batches = sys.argv[1:] iflen(sys.argv) > 1else [datetime.now().strftime("%Y%m%d") + h for h in ("00", "12")]    logger.info(f"开始 {len(batches)} 批次")    ok = fail = 0    for b insorted(batches):        if download_one(b):            ok += 1        else:            fail += 1    logger.info(f"完成 OK={ok} FAIL={fail}")

CMA-GFS气象数据转换到Zarr格式技术解析

全球气候变暖让飞机更颠簸了吗?

短波通信频率预测模型——从电离层到可用频率工程

GPM IMERG 全球降水数据(NASA)完整下载教程

沉寂近40年!南极巨无霸A23a冰山解体,背后藏着地球气候大信号

最新文章

随机文章