42 lines
1.6 KiB
Go
42 lines
1.6 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package integrate
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
|
|
"sourcedock.dev/petrbalvin/tensor/internal/core"
|
|
)
|
|
|
|
// TestFixedStepTimeGrid pins the exact time grid of the fixed-step
|
|
// solvers: the stage times come from t0 + i·h, never from an
|
|
// accumulated t += h, whose rounding walks over a long run. On
|
|
// y' = cos t from t0 = 1e6 the walk used to hold the answer at an
|
|
// error of 1.1e-8 that no step count refined away; the grid puts RK4
|
|
// at its own truncation floor and lets the first-order schemes show
|
|
// their h. The tolerances sit an order below the old walk, so the pin
|
|
// fails on an accumulated-time build.
|
|
func TestFixedStepTimeGrid(t *testing.T) {
|
|
const t0, span, steps = 1e6, 1e-1, 1e5
|
|
cos := func(t float64, y *core.Array) (*core.Array, error) {
|
|
return core.FromFloats([]float64{math.Cos(t)}, 1)
|
|
}
|
|
exact := math.Sin(t0 + span)
|
|
end, err := IntegrateRK4(cos, t0, t0+span, mustFloats(t, []float64{math.Sin(t0)}), steps)
|
|
if err != nil {
|
|
t.Fatalf("IntegrateRK4: %v", err)
|
|
}
|
|
if got := math.Abs(end.FloatAt(0) - exact); got > 1e-11 {
|
|
t.Fatalf("RK4 error %.3e exceeds 1e-11: the stage times have left the exact grid", got)
|
|
}
|
|
end, err = IntegrateBackwardEuler(cos, t0, t0+span, mustFloats(t, []float64{math.Sin(t0)}), 1e6, ODEOptions{})
|
|
if err != nil {
|
|
t.Fatalf("IntegrateBackwardEuler: %v", err)
|
|
}
|
|
if got := math.Abs(end.FloatAt(0) - exact); got > 5e-9 {
|
|
t.Fatalf("backward Euler error %.3e exceeds 5e-9: the step times have left the exact grid", got)
|
|
}
|
|
}
|