# 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()