fix(input): correct lon mapping
This commit is contained in:
parent
19557f3a62
commit
84d1664b29
20 changed files with 1197 additions and 137 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package windviz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -94,3 +96,86 @@ func TestCacheRoundTrip(t *testing.T) {
|
|||
t.Errorf("cache should hit after put")
|
||||
}
|
||||
}
|
||||
|
||||
// horizonWind has data up to horizon seconds and fails past it, the way a real
|
||||
// dataset's time axis does.
|
||||
type horizonWind struct{ horizon float64 }
|
||||
|
||||
func (w horizonWind) Wind(t, _, _, _ float64) (weather.Sample, error) {
|
||||
if t > w.horizon {
|
||||
return weather.Sample{}, fmt.Errorf("hour=%v out of range", t/3600)
|
||||
}
|
||||
return weather.Sample{U: 7, V: -3}, nil
|
||||
}
|
||||
func (w horizonWind) Epoch() time.Time { return time.Unix(0, 0).UTC() }
|
||||
func (w horizonWind) Source() string { return "test" }
|
||||
|
||||
// northOnlyWind has data only in the northern hemisphere, the way a regional
|
||||
// subset does. Its failures are genuinely per-cell.
|
||||
type northOnlyWind struct{}
|
||||
|
||||
func (northOnlyWind) Wind(_, lat, _, _ float64) (weather.Sample, error) {
|
||||
if lat < 0 {
|
||||
return weather.Sample{}, fmt.Errorf("lat=%v outside region", lat)
|
||||
}
|
||||
return weather.Sample{U: 5, V: 1}, nil
|
||||
}
|
||||
func (northOnlyWind) Epoch() time.Time { return time.Unix(0, 0).UTC() }
|
||||
func (northOnlyWind) Source() string { return "test" }
|
||||
|
||||
// TestRasterizeRefusesWhenNoCellHasData is the case the package comment already
|
||||
// promised and the code never implemented ("a time outside coverage is a hard
|
||||
// error").
|
||||
//
|
||||
// Time is one value for the whole request, so a time past the dataset's horizon
|
||||
// fails every cell. Each failure was written as a zero, so the response was a
|
||||
// complete grid of zero wind — a velocity layer draws that as an atmosphere at
|
||||
// perfect rest. Missing data must not be rendered as calm air.
|
||||
func TestRasterizeRefusesWhenNoCellHasData(t *testing.T) {
|
||||
f := horizonWind{horizon: 600}
|
||||
|
||||
out, err := Rasterize(f, Request{Time: 700, MinLng: 0, MaxLng: 360, Step: 90})
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("Rasterize returned %d components instead of an error", len(out))
|
||||
}
|
||||
if !strings.Contains(err.Error(), "out of range") {
|
||||
t.Errorf("error %q does not carry the sampler's reason", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRasterizeStillSucceedsWithinCoverage keeps the check above from rejecting
|
||||
// healthy requests.
|
||||
func TestRasterizeStillSucceedsWithinCoverage(t *testing.T) {
|
||||
f := horizonWind{horizon: 600}
|
||||
|
||||
out, err := Rasterize(f, Request{Time: 300, MinLng: 0, MaxLng: 360, Step: 90})
|
||||
if err != nil {
|
||||
t.Fatalf("Rasterize within coverage: %v", err)
|
||||
}
|
||||
if got := out[0].Data[0]; got != 7 {
|
||||
t.Errorf("u = %v, want 7", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRasterizeZeroFillsIndividualGaps preserves the documented per-cell
|
||||
// behaviour: a partly-covered grid is still worth drawing, so gaps stay zero and
|
||||
// the request succeeds. Only a grid with nothing in it is refused.
|
||||
func TestRasterizeZeroFillsIndividualGaps(t *testing.T) {
|
||||
out, err := Rasterize(northOnlyWind{}, Request{
|
||||
MinLat: -30, MaxLat: 30, MinLng: 0, MaxLng: 30, Step: 30,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Rasterize partly-covered grid: %v", err)
|
||||
}
|
||||
|
||||
// Row 0 is the northernmost latitude (+30), the last row is -30.
|
||||
nx := out[0].Header.Nx
|
||||
ny := out[0].Header.Ny
|
||||
if got := out[0].Data[0]; got != 5 {
|
||||
t.Errorf("northern cell u = %v, want 5", got)
|
||||
}
|
||||
if got := out[0].Data[(ny-1)*nx]; got != 0 {
|
||||
t.Errorf("southern gap u = %v, want 0", got)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue