Initial import
This commit is contained in:
215
tasks/WeatherServer_GridBuilder_v2.md
Normal file
215
tasks/WeatherServer_GridBuilder_v2.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# NavSea Weather Server
|
||||
Task: WeatherServer_GridBuilder_v2
|
||||
Architecture: NavSea V11
|
||||
Codex: codex6
|
||||
Status: TODO
|
||||
|
||||
---
|
||||
|
||||
# 1 任务目标
|
||||
|
||||
升级 Grid Builder:
|
||||
|
||||
grid_builder.py → GridBuilder v2
|
||||
|
||||
目标:
|
||||
|
||||
1 裁剪日本区域 grid
|
||||
2 使用数组结构保存 grid
|
||||
3 大幅减少 JSON 文件大小
|
||||
|
||||
---
|
||||
|
||||
# 2 当前问题
|
||||
|
||||
旧版 GridBuilder:
|
||||
|
||||
生成全球 grid:
|
||||
|
||||
1440 × 721
|
||||
≈ 1,038,240 points
|
||||
|
||||
JSON 文件:
|
||||
|
||||
≈ 215MB
|
||||
|
||||
这是不可接受的。
|
||||
|
||||
Downloader 已经只下载:
|
||||
|
||||
120E – 150E
|
||||
20N – 50N
|
||||
|
||||
GridBuilder 必须只输出这个区域。
|
||||
|
||||
---
|
||||
|
||||
# 3 区域范围
|
||||
|
||||
REGION:
|
||||
|
||||
lon_min = 120
|
||||
lon_max = 150
|
||||
|
||||
lat_min = 20
|
||||
lat_max = 50
|
||||
|
||||
理论 grid:
|
||||
|
||||
(150-120)/0.25 = 120
|
||||
(50-20)/0.25 = 120
|
||||
|
||||
≈ 14400 grid points
|
||||
|
||||
---
|
||||
|
||||
# 4 新 Grid 数据结构
|
||||
|
||||
旧结构:
|
||||
|
||||
points list
|
||||
|
||||
{
|
||||
"points":[
|
||||
{lat,lon,...}
|
||||
]
|
||||
}
|
||||
|
||||
新结构:
|
||||
|
||||
grid arrays
|
||||
|
||||
{
|
||||
"time": "...",
|
||||
"lat": [...],
|
||||
"lon": [...],
|
||||
"wind_speed": [...],
|
||||
"wind_dir": [...],
|
||||
"rain": [...],
|
||||
"temp": [...],
|
||||
"pressure": [...]
|
||||
}
|
||||
|
||||
优点:
|
||||
|
||||
1 文件更小
|
||||
2 读取更快
|
||||
3 tile generator 更容易
|
||||
|
||||
---
|
||||
|
||||
# 5 创建文件
|
||||
|
||||
weather_server/grid/grid_builder_v2.py
|
||||
|
||||
---
|
||||
|
||||
# 6 实现代码
|
||||
|
||||
```python
|
||||
import os
|
||||
import json
|
||||
import numpy as np
|
||||
import xarray as xr
|
||||
|
||||
INPUT_DIR = "data/grib"
|
||||
OUTPUT_DIR = "data/grid"
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
REGION = {
|
||||
"lon_min":120,
|
||||
"lon_max":150,
|
||||
"lat_min":20,
|
||||
"lat_max":50
|
||||
}
|
||||
|
||||
|
||||
def compute_wind(u, v):
|
||||
|
||||
speed = np.sqrt(u**2 + v**2)
|
||||
|
||||
direction = (np.degrees(np.arctan2(u, v)) + 360) % 360
|
||||
|
||||
return speed, direction
|
||||
|
||||
|
||||
def process_file(path):
|
||||
|
||||
ds = xr.open_dataset(path, engine="cfgrib")
|
||||
|
||||
u = ds["u10"].values
|
||||
v = ds["v10"].values
|
||||
rain = ds["tp"].values
|
||||
pressure = ds["msl"].values
|
||||
temp = ds["t2m"].values
|
||||
|
||||
lat = ds.latitude.values
|
||||
lon = ds.longitude.values
|
||||
|
||||
wind_speed, wind_dir = compute_wind(u, v)
|
||||
|
||||
lat_idx = np.where(
|
||||
(lat >= REGION["lat_min"]) &
|
||||
(lat <= REGION["lat_max"])
|
||||
)[0]
|
||||
|
||||
lon_idx = np.where(
|
||||
(lon >= REGION["lon_min"]) &
|
||||
(lon <= REGION["lon_max"])
|
||||
)[0]
|
||||
|
||||
lat_region = lat[lat_idx]
|
||||
lon_region = lon[lon_idx]
|
||||
|
||||
wind_speed = wind_speed[np.ix_(lat_idx, lon_idx)]
|
||||
wind_dir = wind_dir[np.ix_(lat_idx, lon_idx)]
|
||||
|
||||
rain = rain[np.ix_(lat_idx, lon_idx)]
|
||||
temp = temp[np.ix_(lat_idx, lon_idx)]
|
||||
pressure = pressure[np.ix_(lat_idx, lon_idx)]
|
||||
|
||||
return {
|
||||
"lat": lat_region.tolist(),
|
||||
"lon": lon_region.tolist(),
|
||||
"wind_speed": wind_speed.tolist(),
|
||||
"wind_dir": wind_dir.tolist(),
|
||||
"rain": rain.tolist(),
|
||||
"temp": temp.tolist(),
|
||||
"pressure": pressure.tolist()
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
for file in os.listdir(INPUT_DIR):
|
||||
|
||||
if not file.endswith(".grib2"):
|
||||
continue
|
||||
|
||||
path = os.path.join(INPUT_DIR, file)
|
||||
|
||||
print("processing", file)
|
||||
|
||||
grid = process_file(path)
|
||||
|
||||
output = os.path.join(
|
||||
OUTPUT_DIR,
|
||||
f"grid_{file.replace('.grib2','')}.json"
|
||||
)
|
||||
|
||||
data = {
|
||||
"time": file.replace(".grib2",""),
|
||||
"grid": grid
|
||||
}
|
||||
|
||||
with open(output, "w") as f:
|
||||
|
||||
json.dump(data, f)
|
||||
|
||||
print("saved", output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user