feat(decart): interp
This commit is contained in:
parent
1bd9143186
commit
19557f3a62
14 changed files with 681 additions and 208 deletions
|
|
@ -23,9 +23,11 @@ func TestAxisLocate(t *testing.T) {
|
|||
t.Errorf("Locate(-89.75) = %+v, %v; want frac=0.5", b, err)
|
||||
}
|
||||
|
||||
// 90 is exactly on the upper boundary — there's no Hi above it
|
||||
if _, err := a.Locate(90); err == nil {
|
||||
t.Errorf("Locate(90) should error, got nil")
|
||||
// 90 is exactly on the upper boundary. It is now accepted as the far edge of
|
||||
// the last cell: on the GFS latitude axis that is the north pole, whose row
|
||||
// carries real data. Rejecting it used to freeze predictions there.
|
||||
if b, err := a.Locate(90); err != nil || b.Lo != 359 || b.Hi != 360 || math.Abs(b.Frac-1) > 1e-12 {
|
||||
t.Errorf("Locate(90) = %+v, %v; want {359 360 1}", b, err)
|
||||
}
|
||||
|
||||
if _, err := a.Locate(-91); err == nil {
|
||||
|
|
@ -47,9 +49,16 @@ func TestAxisLocateWrap(t *testing.T) {
|
|||
t.Errorf("Locate(359.75) = %+v, %v; want {719 0 0.5}", b, err)
|
||||
}
|
||||
|
||||
// 360 is outside the half-open interval
|
||||
if _, err := a.Locate(360); err == nil {
|
||||
t.Errorf("Locate(360) should error, got nil")
|
||||
// 360 is the wrap point and now resolves to it: the far edge of the last
|
||||
// cell, whose Hi is index 0. Weight 1 there means exactly 0 degrees, which
|
||||
// is what 360 means. Callers normalise longitude anyway, so this is a
|
||||
// consistency property rather than a path anyone relies on.
|
||||
if b, err := a.Locate(360); err != nil || b.Lo != 719 || b.Hi != 0 || math.Abs(b.Frac-1) > 1e-12 {
|
||||
t.Errorf("Locate(360) = %+v, %v; want {719 0 1}", b, err)
|
||||
}
|
||||
|
||||
if _, err := a.Locate(360.5); err == nil {
|
||||
t.Errorf("Locate(360.5) should error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,3 +101,56 @@ func TestLerp(t *testing.T) {
|
|||
t.Errorf("Lerp(10, 20, 0.25) != 12.5")
|
||||
}
|
||||
}
|
||||
|
||||
// The GFS latitude axis runs -90..90 at 0.5 deg (N=361), so the north pole is
|
||||
// the axis's exact upper bound. Bracketing must accept it: the pole row holds
|
||||
// real data (NCEP resolves it per longitude via POLFIXV), and refusing it made
|
||||
// the whole prediction freeze silently at latitude 90. The same applies to the
|
||||
// last forecast hour and the topmost pressure level.
|
||||
func TestAxisLocateAcceptsExactUpperBound(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
lat := Axis{Left: -90, Step: 0.5, N: 361, Name: "lat"}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
value float64
|
||||
wantLo int
|
||||
wantHi int
|
||||
wantFrac float64
|
||||
}{
|
||||
{name: "exact lower bound", value: -90, wantLo: 0, wantHi: 1, wantFrac: 0},
|
||||
{name: "interior point", value: 0.25, wantLo: 180, wantHi: 181, wantFrac: 0.5},
|
||||
{name: "one cell below the top", value: 89.5, wantLo: 359, wantHi: 360, wantFrac: 0},
|
||||
{name: "inside the top cell", value: 89.75, wantLo: 359, wantHi: 360, wantFrac: 0.5},
|
||||
// The case that used to error: the far edge of the last cell.
|
||||
{name: "exact upper bound is the top of the last cell", value: 90, wantLo: 359, wantHi: 360, wantFrac: 1},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
b, err := lat.Locate(tt.value)
|
||||
if err != nil {
|
||||
t.Fatalf("Locate(%v) returned error: %v", tt.value, err)
|
||||
}
|
||||
if b.Lo != tt.wantLo || b.Hi != tt.wantHi {
|
||||
t.Errorf("Locate(%v) = lo %d hi %d, want lo %d hi %d", tt.value, b.Lo, b.Hi, tt.wantLo, tt.wantHi)
|
||||
}
|
||||
if math.Abs(b.Frac-tt.wantFrac) > 1e-12 {
|
||||
t.Errorf("Locate(%v) frac = %v, want %v", tt.value, b.Frac, tt.wantFrac)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAxisLocateStillRejectsOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
lat := Axis{Left: -90, Step: 0.5, N: 361, Name: "lat"}
|
||||
for _, v := range []float64{-90.001, 90.001, 91, -100} {
|
||||
if _, err := lat.Locate(v); err == nil {
|
||||
t.Errorf("Locate(%v) accepted a value outside the axis", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue