Initial import of NavSea pbf project

This commit is contained in:
OpenAI Codex
2026-03-17 19:48:15 +08:00
commit 5f3f7409b3
84 changed files with 43889 additions and 0 deletions

264
tasks/updatedownload.md Normal file
View File

@@ -0,0 +1,264 @@
# 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
---
# 新代码
```python
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()