package numerics import ( "math" "testing" ) func TestAxisLocate(t *testing.T) { a := Axis{Left: -90, Step: 0.5, N: 361, Name: "lat"} b, err := a.Locate(-90) if err != nil || b.Lo != 0 || b.Hi != 1 || b.Frac != 0 { t.Errorf("Locate(-90) = %+v, %v; want {0 1 0}, nil", b, err) } b, err = a.Locate(0) if err != nil || b.Lo != 180 || b.Hi != 181 || b.Frac != 0 { t.Errorf("Locate(0) = %+v, %v; want {180 181 0}, nil", b, err) } b, err = a.Locate(-89.75) if err != nil || b.Lo != 0 || b.Hi != 1 || math.Abs(b.Frac-0.5) > 1e-12 { 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") } if _, err := a.Locate(-91); err == nil { t.Errorf("Locate(-91) should error, got nil") } } func TestAxisLocateWrap(t *testing.T) { a := Axis{Left: 0, Step: 0.5, N: 720, Wrap: true, Name: "lng"} b, err := a.Locate(0) if err != nil || b.Lo != 0 || b.Hi != 1 || b.Frac != 0 { t.Errorf("Locate(0) = %+v, %v", b, err) } // Right up against the wrap boundary b, err = a.Locate(359.75) if err != nil || b.Lo != 719 || b.Hi != 0 || math.Abs(b.Frac-0.5) > 1e-12 { 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") } } func TestEvalTrilinear(t *testing.T) { // Field f(i,j,k) = 100*i + 10*j + k. f := func(i, j, k int) float64 { return 100*float64(i) + 10*float64(j) + float64(k) } // At all fractions = 0.5, expected value is the mean of the 8 corners. bs := [3]Bracket{{Lo: 0, Hi: 1, Frac: 0.5}, {Lo: 0, Hi: 1, Frac: 0.5}, {Lo: 0, Hi: 1, Frac: 0.5}} got := EvalTrilinear(bs, f) want := (0 + 1 + 10 + 11 + 100 + 101 + 110 + 111) / 8.0 if math.Abs(got-want) > 1e-12 { t.Errorf("EvalTrilinear at center = %v, want %v", got, want) } // At all fractions = 0, expected value is f(lo, lo, lo) = 0. bs = [3]Bracket{{Lo: 0, Hi: 1, Frac: 0}, {Lo: 0, Hi: 1, Frac: 0}, {Lo: 0, Hi: 1, Frac: 0}} got = EvalTrilinear(bs, f) if got != 0 { t.Errorf("EvalTrilinear at (lo,lo,lo) = %v, want 0", got) } // Asymmetric: linear field f(i,j,k) = i should give frac of axis 0 exactly. f2 := func(i, _, _ int) float64 { return float64(i) } bs = [3]Bracket{{Lo: 0, Hi: 1, Frac: 0.3}, {Lo: 0, Hi: 1, Frac: 0.7}, {Lo: 0, Hi: 1, Frac: 0.9}} got = EvalTrilinear(bs, f2) if math.Abs(got-0.3) > 1e-12 { t.Errorf("EvalTrilinear of i-field = %v, want 0.3", got) } } func TestLerp(t *testing.T) { if Lerp(10, 20, 0) != 10 { t.Errorf("Lerp(10, 20, 0) != 10") } if Lerp(10, 20, 1) != 20 { t.Errorf("Lerp(10, 20, 1) != 20") } if math.Abs(Lerp(10, 20, 0.25)-12.5) > 1e-12 { t.Errorf("Lerp(10, 20, 0.25) != 12.5") } }