updated downloader

This commit is contained in:
straitz 2026-03-22 16:29:53 +09:00
parent ca95e06ab7
commit 8e9f117799
30 changed files with 1209 additions and 698 deletions

View file

@ -4,30 +4,100 @@ import "math"
func lerp(a, b, t float64) float64 { return a + t*(b-a) }
// Interpolate 16point (time, p, lat, lon)
// ghInterp returns interpolated geopotential height at given time/pressure/lat/lon
func (d *dataset) ghInterp(ti, pi int, y0, y1, x0, x1 int, wy, wx float64) float64 {
g00 := d.cube.val(0, ti, pi, y0, x0)
g10 := d.cube.val(0, ti, pi, y0, x1)
g01 := d.cube.val(0, ti, pi, y1, x0)
g11 := d.cube.val(0, ti, pi, y1, x1)
return (1-wy)*((1-wx)*float64(g00)+wx*float64(g10)) + wy*((1-wx)*float64(g01)+wx*float64(g11))
}
// searchAltLevel uses geopotential height to find pressure level bracket for target altitude.
func (d *dataset) searchAltLevel(alt float64, ti, y0, y1, x0, x1 int, wy, wx float64) (int, float64) {
levels := d.ds.Levels
nLevels := len(levels)
lo, hi := 0, nLevels-1
for lo < hi-1 {
mid := (lo + hi) / 2
ghMid := d.ghInterp(ti, mid, y0, y1, x0, x1, wy, wx)
if ghMid < alt {
lo = mid
} else {
hi = mid
}
}
ghLo := d.ghInterp(ti, lo, y0, y1, x0, x1, wy, wx)
ghHi := d.ghInterp(ti, hi, y0, y1, x0, x1, wy, wx)
wp := 0.0
if ghHi != ghLo {
wp = (alt - ghLo) / (ghHi - ghLo)
}
if wp < 0 {
wp = 0
}
if wp > 1 {
wp = 1
}
return lo, wp
}
// uv выполняет интерполяцию ветра по 4 измерениям (time, pressure, lat, lon).
func (d *dataset) uv(lat, lon, alt float64, tHours float64) (float64, float64) {
if lon < 0 {
lon += 360
}
iy := (lat + 90) * 2
inv := d.ds.InvResolution()
// GRIB scan north→south: index 0 = 90°N
iy := (90 - lat) * inv
y0 := int(math.Floor(iy))
if y0 < 0 {
y0 = 0
}
if y0 >= d.cube.lat-1 {
y0 = d.cube.lat - 2
}
y1 := y0 + 1
wy := iy - float64(y0)
ix := lon * 2
ix := lon * inv
x0 := int(math.Floor(ix)) % d.cube.lon
x1 := (x0 + 1) % d.cube.lon
wx := ix - float64(x0)
// For 3-hourly data (step = 3 hours)
// Convert tHours to 3-hour index (e.g., 1.5 hours -> index 0.5, interpolate between 0 and 1)
it0 := int(math.Floor(tHours / 3.0))
wt := (tHours - float64(it0*3)) / 3.0 // Interpolation weight within 3-hour window
// Время: tHours делим на шаг, чтобы получить индекс в кубе
tIdx := tHours / float64(d.ds.TimeStep)
it0 := int(math.Floor(tIdx))
if it0 < 0 {
it0 = 0
}
if it0 >= d.cube.t-1 {
it0 = d.cube.t - 2
}
wt := tIdx - float64(it0)
// ISA: высота → давление → индекс уровня
levels := d.ds.Levels
p := pressureFromAlt(alt)
ip0 := 0
for ip0+1 < len(pressureLevels) && pressureLevels[ip0+1] > p {
for ip0+1 < len(levels) && levels[ip0+1] > p {
ip0++
}
ip1 := ip0 + 1
wp := (pressureLevels[ip0] - p) / (pressureLevels[ip0] - pressureLevels[ip1])
if ip1 >= len(levels) {
ip1 = len(levels) - 1
}
wp := 0.0
if levels[ip0] != levels[ip1] {
wp = (levels[ip0] - p) / (levels[ip0] - levels[ip1])
}
fetch := func(ti, pi int) (float64, float64) {
u00 := d.cube.val(1, ti, pi, y0, x0)
u10 := d.cube.val(1, ti, pi, y0, x1)
@ -41,6 +111,7 @@ func (d *dataset) uv(lat, lon, alt float64, tHours float64) (float64, float64) {
vxy := (1-wy)*((1-wx)*float64(v00)+wx*float64(v10)) + wy*((1-wx)*float64(v01)+wx*float64(v11))
return uxy, vxy
}
u0p0, v0p0 := fetch(it0, ip0)
u0p1, v0p1 := fetch(it0, ip1)
u1p0, v1p0 := fetch(it0+1, ip0)