再分析资料ERA5下载的保姆式教程

ERA5再分析资料下载

本教程使用Docker容器化Python环境与Python脚本进行下载,同时使用了Cron 服务进行定时下载,脚本及镜像Dockerfile都已提供,只需要简单的步骤和环境即可实现定时从Copernicus Climate Data官网下载再分析资料数据。(你也可以直接在服务器上安装python3环境及cds客户端执行脚本,这里使用Docker Python容器环境执行是一样的,使用Docker主要好处就是不影响宿主机环境)

服务器环境要求

  • 服务器需要已安装Docker
  • 服务器需要已安装 Cron 服务(大部分CentOS/RHEL 系统都会自带)
  • 需要自己注册CDS账号并获取对应的url和key,同时记得在官网同意他的下载协议!否则脚本下载时会报错提示的,即时遇到报错提示了也可以访问报错提示中的地址去同意,问题不大。 (地址:https://cds.climate.copernicus.eu/how-to-api)

构建镜像

  • Dockerfile
# Python 语言容器镜像
FROM python:3.10-slim-buster

# 设置工作目录为 /workspace
WORKDIR /workspace

# 创建 data 文件夹用于存储数据
RUN mkdir -p /workspace/data \
    && chmod -R 777 /workspace/data

# 更新 pip
RUN python -m pip install --upgrade pip

# 安装 cdsapi 客户端
RUN pip install cdsapi

# 创建日志文件目录
RUN mkdir -p /workspace/logs \
	&& chmod -R 777 /workspace/logs  # 确保容器有写入权限

# 容器启动时不启动 cron,而是通过宿主机的 cron 来执行
CMD ["tail", "-f", "/dev/null"]

  • Copernicus Climate 官网建议使用Python 3 以上版本
  • 因为Docker 镜像官网国内已经用不了了或者各种网络导致的问题,这里也为你贴心给你已经打包好的镜像了。( 百度网盘地址:网盘链接)
#加载 Docker 镜像
docker load -i era5-python-image.tar

配置文件

  • 新建编辑CDS客户端配置文件,注意your_api_key_here是自己账号的api key
  • 这里直接在宿主机上编辑CDS所需的配置文件,然后映射到容器中,方便直接修改和配置
mkdir -p /workspace
echo "url : https://cds.climate.copernicus.eu/api" > /workspace/.cdsapirc
echo "key : your_api_key_here" >> /workspace/.cdsapirc

启动python容器

  • 将配置文件、脚本文件及下载目录映射至容器
docker run -d --name era5-python-container -v /home/python/.cdsapirc:/root/.cdsapirc -v /home/python/workspace:/workspace era5-python-image  

配置cron定时执行脚本文件

  • 这里没有直接使用容器执行脚本,选择容器bash方式执行脚本,方便后台执行时记录控制台输出日志到download_log
# 打开宿主机的 cron 配置文件进行编辑配置
crontab -e
# 添加一行 执行再分析资料下载定时任务 每天凌晨三点执行一次
0 3 * * * docker exec -d era5-python-container bash -c "python /workspace/era5.py >> /workspace/logs/download_log.log 2>&1"

# 查看 Cron 执行日志
tail -f /var/log/syslog     # Debian/Ubuntu 系统
tail -f /var/log/cron       # CentOS/RHEL 系统

# 启动 cron 服务
sudo service cron start # 对于 Ubuntu/Debian
sudo systemctl start crond # 对于 CentOS/RHEL

# cron 服务开机自动启动
sudo systemctl enable cron # 对于 Ubuntu/Debian
sudo systemctl enable crond # 对于 CentOS/RHEL
  • 添加定时任务之前可以手动测试执行一次脚本
docker exec -it era5-python-container python /workspace/era5.py >> /workspace/logs/era5.log 2>&1

Python下载脚本代码

  • 脚本很简单,就不放文件了
  • 脚本下载的数据可以自己根据自己的需求调整层级、变量、时间等等
  • 注意 Copernicus Climate官网提供的数据最新时间是七天前
import cdsapi
import datetime
import pathlib

# 创建 cdsapi 客户端
c = cdsapi.Client()

def get_latest_date_from_var_directory(var_directory: pathlib.Path):
    """
    获取指定变量目录中最新 .nc 文件的日期,并返回日期。
    """
    latest_date = None
    
    # 获取当前变量目录下的所有 .nc 文件
    nc_files = list(var_directory.glob('*.nc'))
    if not nc_files:
        return None  # 如果当前目录下没有 .nc 文件,返回 None
    
    # 获取文件的日期部分,文件名格式假设为 'era5.variable.YYYYMMDD.nc'
    for file in nc_files:
        try:
            date_str = file.stem.split('.')[-1]  # 获取文件名中的日期部分
            file_date = datetime.datetime.strptime(date_str, '%Y%m%d')
            if latest_date is None or file_date > latest_date:
                latest_date = file_date
        except ValueError:
            continue
    
    return latest_date  # 返回最新的日期

def download_era5_data(variable, date, savepath):
    """
    下载 ERA5 数据并保存为 .nc 文件
    """
    try:
        c.retrieve(
            'reanalysis-era5-pressure-levels',
            {
                'product_type': 'reanalysis',
                'grid': '0.25/0.25',
                'area': [70, 40, 0, 140],  # latitudes and longitudes
                'format': 'netcdf',
                'variable': variable,
                'pressure_level': ['1', '50', '100', '125', '150', '175', '200', '225', '250', '300', '350', '400', 
                                   '450', '500', '550', '600', '650', '700', '750', '775', '800', '825', '850', '875', 
                                   '900', '925', '950', '975', '1000'],
                'year': date.strftime('%Y'),
                'month': date.strftime('%m'),
                'day': date.strftime('%d'),
                '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']
            },
            savepath
        )
        print(f"Downloaded {variable} for {date.strftime('%Y-%m-%d')}")
    except Exception as e:
        print(f"Error downloading {variable} for {date.strftime('%Y-%m-%d')}: {str(e)}")

def main():
    # 设置保存路径
    savebase = pathlib.Path('/workspace/data')
    savebase.mkdir(parents=True, exist_ok=True)

    # 获取当前日期的七天前
    seven_days_ago = datetime.datetime.today() - datetime.timedelta(days=7)

    var_list = [
        'divergence', 'fraction_of_cloud_cover', 'geopotential', 'ozone_mass_mixing_ratio',
        'potential_vorticity', 'relative_humidity', 'specific_cloud_ice_water_content',
        'specific_cloud_liquid_water_content', 'specific_humidity', 'specific_rain_water_content',
        'specific_snow_water_content', 'temperature', 'u_component_of_wind', 'v_component_of_wind',
        'vertical_velocity', 'vorticity'
    ]
    
    # 遍历变量列表
    for var in var_list:
        # 获取每个变量对应的文件夹路径
        var_directory = savebase / var
        var_directory.mkdir(parents=True, exist_ok=True)
        
        # 获取当前变量文件夹中的最新文件日期
        latest_date = get_latest_date_from_var_directory(var_directory)
        
        if latest_date is None:
            # 如果没有找到文件,默认从起始日期开始
            pre_begin = datetime.datetime.strptime('20241101', '%Y%m%d')
        else:
            # 比较当前日期的七天前与最新文件日期
            if latest_date.date() == seven_days_ago.date():
                print(f"{var} 的最新文件已经下载完毕,无需重复下载。")
                continue  # 如果最新文件的日期等于当前时间七天前,跳过该变量的下载

            pre_begin = latest_date + datetime.timedelta(days=1)  # 从最新文件的下一天开始

        # 截止日期为当前日期的七天之前
        end = seven_days_ago

        # 循环下载数据,直到截止日期
        current_date = pre_begin
        while current_date <= end:
            download_era5_data(var, current_date, var_directory / f"era5.{var}.{current_date.strftime('%Y%m%d')}.nc")
            current_date += datetime.timedelta(days=1)

if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值