Files
pbf/tasks/updatedownload.md
2026-03-17 19:48:15 +08:00

3.6 KiB
Raw Blame History

NavSea Weather Server

Task: WeatherServer_GFS_Subset_Downloader Architecture: V11 Codex: codex6 Status: TODO


任务目标

升级现有 gfs_downloader.py

当前问题:

直接下载完整 GFS 文件:

gfs.t00z.pgrb2.0p25.f000

文件大小:

≈ 500MB

下载 72 小时预测需要:

≈ 12GB

这是不可接受的。

解决方案:

使用 NOAA 提供的 GRIB Subset API

filter_gfs_0p25.pl

只下载:

1 指定区域 2 指定变量 3 指定高度层

目标:

将单个 GRIB 文件缩小到:

2MB 10MB


下载区域

NavSea 天气服务器只需要日本附近区域:

leftlon = 120 rightlon = 150 toplat = 50 bottomlat = 20

覆盖:

日本海 东海 太平洋日本海域


下载变量

Weather System V1 需要以下变量:

UGRD VGRD APCP PRMSL TMP HTSGW DIRPW PERPW

说明:

UGRD VGRD → 风 APCP → 降水 PRMSL → 气压 TMP → 温度 HTSGW → 浪高 DIRPW → 浪方向 PERPW → 浪周期

变量参数来自 NOAA GFS 参数列表。 :contentReference[oaicite:0]{index=0}


下载高度层

需要以下层:

10 m above ground surface mean sea level

参数:

lev_10_m_above_ground lev_surface lev_mean_sea_level


URL 构造规则

基础地址:

https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25.pl

示例:

https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25.pl? file=gfs.t00z.pgrb2.0p25.f003 &lev_10_m_above_ground=on &lev_surface=on &lev_mean_sea_level=on &var_UGRD=on &var_VGRD=on &var_APCP=on &var_PRMSL=on &var_TMP=on &var_HTSGW=on &var_DIRPW=on &var_PERPW=on &leftlon=120 &rightlon=150 &toplat=50 &bottomlat=20 &dir=%2Fgfs.20260312%2F00%2Fatmos


修改文件

weather_server/downloader/gfs_downloader.py


新代码

import os
import requests
from datetime import datetime

BASE_URL = "https://nomads.ncep.noaa.gov/cgi-bin/filter_gfs_0p25.pl"

OUTPUT_DIR = "data/grib"

FORECAST_HOURS = [
0,3,6,9,12,15,18,21,24,
27,30,33,36,39,42,45,
48,51,54,57,60,63,66,
69,72
]

REGION = {
"leftlon":120,
"rightlon":150,
"toplat":50,
"bottomlat":20
}

VARIABLES = [
"UGRD",
"VGRD",
"APCP",
"PRMSL",
"TMP",
"HTSGW",
"DIRPW",
"PERPW"
]

LEVELS = [
"lev_10_m_above_ground",
"lev_surface",
"lev_mean_sea_level"
]

os.makedirs(OUTPUT_DIR, exist_ok=True)


def get_cycle():

    now = datetime.utcnow()

    hour = (now.hour // 6) * 6

    cycle = f"{hour:02d}"

    date = now.strftime("%Y%m%d")

    return date, cycle


def build_url(date, cycle, fh):

    filename = f"gfs.t{cycle}z.pgrb2.0p25.f{fh}"

    params = {
        "file": filename,
        "leftlon": REGION["leftlon"],
        "rightlon": REGION["rightlon"],
        "toplat": REGION["toplat"],
        "bottomlat": REGION["bottomlat"],
        "dir": f"/gfs.{date}/{cycle}/atmos"
    }

    for v in VARIABLES:
        params[f"var_{v}"] = "on"

    for l in LEVELS:
        params[l] = "on"

    return BASE_URL, params


def download_file(url, params, path):

    if os.path.exists(path):
        print("skip", path)
        return

    print("downloading", path)

    r = requests.get(url, params=params, stream=True)

    if r.status_code != 200:
        print("failed", r.status_code)
        return

    with open(path, "wb") as f:
        for chunk in r.iter_content(1024*1024):
            f.write(chunk)


def main():

    date, cycle = get_cycle()

    print("cycle:", date, cycle)

    for fh in FORECAST_HOURS:

        fh_str = f"{fh:03d}"

        url, params = build_url(date, cycle, fh_str)

        output = os.path.join(
            OUTPUT_DIR,
            f"{date}_{cycle}_f{fh_str}.grib2"
        )

        download_file(url, params, output)


if __name__ == "__main__":
    main()