diff --git a/README.md b/README.md index c3ac44c8..8a326579 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ corresponding to `(u,t)` pairs. + `pVec` - Symbol to Parameters Vector, `pVec = :Uniform` for uniform spaced parameters and `pVec = :ArcLen` for parameters generated by chord length method. + `knotVec` - Symbol to Knot Vector, `knotVec = :Uniform` for uniform knot vector, `knotVec = :Average` for average spaced knot vector. - `BSplineApprox(u,t,d,h,pVec,knotVec)` - A regression B-spline which smooths the fitting curve. The argument choices are the same as the `BSplineInterpolation`, with the additional parameter `h !in(x, t), trange) @testset "$name" begin @@ -25,7 +26,8 @@ function test_derivatives(method, u, t; args = [], kwargs = [], name::String) # Interpolation time points for _t in t[2:(end - 1)] - if func isa BSplineInterpolation || func isa BSplineApprox + if func isa BSplineInterpolation || func isa BSplineApprox || + func isa CubicHermiteSpline fdiff = forward_fdm(5, 1; geom = true)(func, _t) fdiff2 = forward_fdm(5, 1; geom = true)(t -> derivative(func, t), _t) else @@ -65,7 +67,7 @@ function test_derivatives(method, u, t; args = [], kwargs = [], name::String) end @test_throws DataInterpolations.DerivativeNotFoundError derivative( func, t[1], 3) - func = method(u, t, args...) + func = method(args...) @test_throws DataInterpolations.ExtrapolationError derivative(func, t[1] - 1.0) @test_throws DataInterpolations.ExtrapolationError derivative(func, t[end] + 1.0) @test_throws DataInterpolations.DerivativeNotFoundError derivative( @@ -75,52 +77,47 @@ end @testset "Linear Interpolation" begin u = vcat(collect(1:5), 2 * collect(6:10)) t = 1.0collect(1:10) - test_derivatives(LinearInterpolation, u, t; name = "Linear Interpolation (Vector)") + test_derivatives( + LinearInterpolation; args = [u, t], name = "Linear Interpolation (Vector)") u = vcat(2.0collect(1:10)', 3.0collect(1:10)') - test_derivatives(LinearInterpolation, u, t; name = "Linear Interpolation (Matrix)") + test_derivatives( + LinearInterpolation; args = [u, t], name = "Linear Interpolation (Matrix)") end @testset "Quadratic Interpolation" begin u = [1.0, 4.0, 9.0, 16.0] t = [1.0, 2.0, 3.0, 4.0] - test_derivatives(QuadraticInterpolation, - u, - t; + test_derivatives(QuadraticInterpolation, args = [u, t], name = "Quadratic Interpolation (Vector)") - test_derivatives(QuadraticInterpolation, - u, - t; - args = [:Backward], + test_derivatives(QuadraticInterpolation; + args = [u, t, :Backward], name = "Quadratic Interpolation (Vector), backward") u = [1.0 4.0 9.0 16.0; 1.0 4.0 9.0 16.0] - test_derivatives(QuadraticInterpolation, - u, - t; + test_derivatives(QuadraticInterpolation; + args = [u, t], name = "Quadratic Interpolation (Matrix)") end @testset "Lagrange Interpolation" begin u = [1.0, 4.0, 9.0] t = [1.0, 2.0, 3.0] - test_derivatives(LagrangeInterpolation, u, t; name = "Lagrange Interpolation (Vector)") + test_derivatives( + LagrangeInterpolation; args = [u, t], name = "Lagrange Interpolation (Vector)") u = [1.0 4.0 9.0; 1.0 2.0 3.0] - test_derivatives(LagrangeInterpolation, u, t; name = "Lagrange Interpolation (Matrix)") + test_derivatives( + LagrangeInterpolation; args = [u, t], name = "Lagrange Interpolation (Matrix)") u = [[1.0, 4.0, 9.0], [3.0, 7.0, 4.0], [5.0, 4.0, 1.0]] - test_derivatives(LagrangeInterpolation, - u, - t; + test_derivatives(LagrangeInterpolation; args = [u, t], name = "Lagrange Interpolation (Vector of Vectors)") u = [[3.0 1.0 4.0; 1.0 5.0 9.0], [2.0 6.0 5.0; 3.0 5.0 8.0], [9.0 7.0 9.0; 3.0 2.0 3.0]] - test_derivatives(LagrangeInterpolation, - u, - t; + test_derivatives(LagrangeInterpolation; args = [u, t], name = "Lagrange Interpolation (Vector of Matrices)") end @testset "Akima Interpolation" begin u = [0.0, 2.0, 1.0, 3.0, 2.0, 6.0, 5.5, 5.5, 2.7, 5.1, 3.0] t = collect(0.0:10.0) - test_derivatives(AkimaInterpolation, u, t; name = "Akima Interpolation") + test_derivatives(AkimaInterpolation; args = [u, t], name = "Akima Interpolation") @testset "Akima smooth derivative at end points" begin A = AkimaInterpolation(u, t) @test derivative(A, t[1]) ≈ derivative(A, nextfloat(t[1])) @@ -131,56 +128,44 @@ end @testset "Quadratic Spline" begin u = [0.0, 1.0, 3.0] t = [-1.0, 0.0, 1.0] - test_derivatives(QuadraticSpline, u, t; name = "Quadratic Interpolation (Vector)") + test_derivatives( + QuadraticSpline; args = [u, t], name = "Quadratic Interpolation (Vector)") u = [[1.0, 2.0, 9.0], [3.0, 7.0, 5.0], [5.0, 4.0, 1.0]] - test_derivatives(QuadraticSpline, - u, - t; + test_derivatives(QuadraticSpline; args = [u, t], name = "Quadratic Interpolation (Vector of Vectors)") u = [[1.0 4.0 9.0; 5.0 9.0 2.0], [3.0 7.0 4.0; 6.0 5.0 3.0], [5.0 4.0 1.0; 2.0 3.0 8.0]] - test_derivatives(QuadraticSpline, - u, - t; + test_derivatives(QuadraticSpline; args = [u, t], name = "Quadratic Interpolation (Vector of Matrices)") end @testset "Cubic Spline" begin u = [0.0, 1.0, 3.0] t = [-1.0, 0.0, 1.0] - test_derivatives(CubicSpline, u, t; name = "Cubic Spline Interpolation (Vector)") + test_derivatives( + CubicSpline; args = [u, t], name = "Cubic Spline Interpolation (Vector)") u = [[1.0, 2.0, 9.0], [3.0, 7.0, 5.0], [5.0, 4.0, 1.0]] - test_derivatives(CubicSpline, - u, - t; + test_derivatives(CubicSpline; args = [u, t], name = "Cubic Spline Interpolation (Vector of Vectors)") u = [[1.0 4.0 9.0; 5.0 9.0 2.0], [3.0 7.0 4.0; 6.0 5.0 3.0], [5.0 4.0 1.0; 2.0 3.0 8.0]] - test_derivatives(CubicSpline, - u, - t; + test_derivatives(CubicSpline; args = [u, t], name = "Cubic Spline Interpolation (Vector of Matrices)") end @testset "BSplines" begin t = [0, 62.25, 109.66, 162.66, 205.8, 252.3] u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] - test_derivatives(BSplineInterpolation, - u, - t; - args = [2, + test_derivatives(BSplineInterpolation; + args = [u, t, 2, :Uniform, :Uniform], name = "BSpline Interpolation (Uniform, Uniform)") - test_derivatives(BSplineInterpolation, - u, - t; - args = [2, + test_derivatives(BSplineInterpolation; + args = [u, t, 2, :ArcLen, :Average], name = "BSpline Interpolation (Arclen, Average)") - test_derivatives(BSplineApprox, - u, - t; - args = [ + test_derivatives(BSplineApprox; + args = [u, t, 3, 4, :Uniform, @@ -188,6 +173,32 @@ end name = "BSpline Approx (Uniform, Uniform)") end +@testset "Cubic Hermite Spline" begin + du = [-0.047, -0.058, 0.054, 0.012, -0.068, 0.0] + u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] + t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3] + test_derivatives(CubicHermiteSpline; args = [du, u, t], + name = "Cubic Hermite Spline") + A = CubicHermiteSpline(du, u, t; extrapolate = true) + @test derivative.(Ref(A), t) ≈ du + @test derivative(A, 100.0)≈0.0105409 rtol=1e-5 + @test derivative(A, 300.0)≈-0.0806717 rtol=1e-5 +end + +@testset "Quintic Hermite Spline" begin + ddu = [0.0, -0.00033, 0.0051, -0.0067, 0.0029, 0.0] + du = [-0.047, -0.058, 0.054, 0.012, -0.068, 0.0] + u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] + t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3] + test_derivatives(QuinticHermiteSpline; args = [ddu, du, u, t], + name = "Quintic Hermite Spline") + A = QuinticHermiteSpline(ddu, du, u, t; extrapolate = true) + @test derivative.(Ref(A), t) ≈ du + @test derivative.(Ref(A), t, 2) ≈ ddu + @test derivative(A, 100.0)≈0.0103916 rtol=1e-5 + @test derivative(A, 300.0)≈0.0331361 rtol=1e-5 +end + @testset "RegularizationSmooth" begin npts = 50 xmin = 0.0 @@ -207,9 +218,7 @@ end tₒ = t[idx] uₒ = u[idx] A = RegularizationSmooth(uₒ, tₒ; alg = :fixed) - test_derivatives(RegularizationSmooth, - uₒ, - tₒ; + test_derivatives(RegularizationSmooth; args = [uₒ, tₒ], kwargs = [:alg => :fixed], name = "RegularizationSmooth") end @@ -220,7 +229,7 @@ end t = range(-10, stop = 10, length = 40) u = model(t, [1.0, 2.0]) + 0.01 * randn(rng, length(t)) p0 = [0.5, 0.5] - test_derivatives(Curvefit, u, t; args = [model, p0, LBFGS()], name = "Curvefit") + test_derivatives(Curvefit; args = [u, t, model, p0, LBFGS()], name = "Curvefit") end @testset "Symbolic derivatives" begin diff --git a/test/integral_tests.jl b/test/integral_tests.jl index 86a5c17f..a5641dff 100644 --- a/test/integral_tests.jl +++ b/test/integral_tests.jl @@ -5,8 +5,9 @@ using Optim, ForwardDiff using RegularizationTools using StableRNGs -function test_integral(method, u, t; args = [], kwargs = [], name::String) - func = method(u, t, args...; kwargs..., extrapolate = true) +function test_integral(method; args = [], kwargs = [], name::String) + func = method(args...; kwargs..., extrapolate = true) + (; t) = func t1 = minimum(t) t2 = maximum(t) @testset "$name" begin @@ -46,7 +47,7 @@ function test_integral(method, u, t; args = [], kwargs = [], name::String) aint = integral(func, (t1 + t2) / 2, t2 + 5.0) @test isapprox(qint, aint, atol = 1e-6, rtol = 1e-8) end - func = method(u, t, args...; kwargs...) + func = method(args...; kwargs...) @test_throws DataInterpolations.ExtrapolationError integral(func, t[1] - 1.0) @test_throws DataInterpolations.ExtrapolationError integral(func, t[end] + 1.0) @test_throws DataInterpolations.ExtrapolationError integral(func, t[1] - 1.0, t[2]) @@ -56,27 +57,27 @@ end @testset "LinearInterpolation" begin u = 2.0collect(1:10) t = 1.0collect(1:10) - test_integral(LinearInterpolation, u, t; name = "Linear Interpolation (Vector)") + test_integral( + LinearInterpolation; args = [u, t], name = "Linear Interpolation (Vector)") u = round.(rand(100), digits = 5) t = 1.0collect(1:100) - test_integral(LinearInterpolation, u, t; + test_integral(LinearInterpolation; args = [u, t], name = "Linear Interpolation (Vector) with random points") end @testset "QuadraticInterpolation" begin u = [1.0, 4.0, 9.0, 16.0] t = [1.0, 2.0, 3.0, 4.0] - test_integral(QuadraticInterpolation, u, t; name = "Quadratic Interpolation (Vector)") + test_integral( + QuadraticInterpolation; args = [u, t], name = "Quadratic Interpolation (Vector)") u = [3.0, 0.0, 3.0, 0.0] t = [1.0, 2.0, 3.0, 4.0] - test_integral(QuadraticInterpolation, - u, - t; - args = [:Backward], + test_integral(QuadraticInterpolation; + args = [u, t, :Backward], name = "Quadratic Interpolation (Vector)") u = round.(rand(100), digits = 5) t = 1.0collect(1:10) - test_integral(QuadraticInterpolation, u, t; + test_integral(QuadraticInterpolation; args = [u, t], name = "Quadratic Interpolation (Vector) with random points") end @@ -91,29 +92,64 @@ end @testset "QuadraticSpline" begin u = [0.0, 1.0, 3.0] t = [-1.0, 0.0, 1.0] - test_integral(QuadraticSpline, u, t; name = "Quadratic Spline (Vector)") + test_integral(QuadraticSpline; args = [u, t], name = "Quadratic Spline (Vector)") u = round.(rand(100), digits = 5) t = 1.0collect(1:100) test_integral( - QuadraticSpline, u, t; name = "Quadratic Spline (Vector) with random points") + QuadraticSpline; args = [u, t], name = "Quadratic Spline (Vector) with random points") end @testset "CubicSpline" begin u = [0.0, 1.0, 3.0] t = [-1.0, 0.0, 1.0] - test_integral(CubicSpline, u, t; name = "Cubic Spline (Vector)") + test_integral(CubicSpline; args = [u, t], name = "Cubic Spline (Vector)") u = round.(rand(100), digits = 5) t = 1.0collect(1:100) - test_integral(CubicSpline, u, t; name = "Cubic Spline (Vector) with random points") + test_integral( + CubicSpline; args = [u, t], name = "Cubic Spline (Vector) with random points") end @testset "AkimaInterpolation" begin u = [0.0, 2.0, 1.0, 3.0, 2.0, 6.0, 5.5, 5.5, 2.7, 5.1, 3.0] t = collect(0.0:10.0) - test_integral(AkimaInterpolation, u, t; name = "Akima Interpolation (Vector)") + test_integral(AkimaInterpolation; args = [u, t], name = "Akima Interpolation (Vector)") + u = round.(rand(100), digits = 5) + t = 1.0collect(1:100) + test_integral( + AkimaInterpolation; args = [u, t], name = "Akima Interpolation (Vector) with random points") +end + +@testset "CubicHermiteSpline" begin + du = [-0.047, -0.058, 0.054, 0.012, -0.068, 0.0] + u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] + t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3] + test_integral(CubicHermiteSpline; args = [du, u, t], + name = "Cubic Hermite Spline (Vector)") + + u = round.(rand(100), digits = 5) + t = 1.0collect(1:100) + du = diff(u) ./ diff(t) + push!(du, 0) + test_integral(CubicHermiteSpline; args = [du, u, t], + name = "Cubic Hermite Spline (Vector) with random points") +end + +@testset "QuinticHermiteSpline" begin + ddu = [0.0, -0.00033, 0.0051, -0.0067, 0.0029, 0.0] + du = [-0.047, -0.058, 0.054, 0.012, -0.068, 0.0] + u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] + t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3] + test_integral(QuinticHermiteSpline; args = [ddu, du, u, t], + name = "Quintic Hermite Spline (Vector)") + u = round.(rand(100), digits = 5) t = 1.0collect(1:100) - test_integral(AkimaInterpolation, u, t; name = "Akima Interpolation (Vector)") + du = diff(u) ./ diff(t) + push!(du, 0) + ddu = diff(du) ./ diff(t) + push!(ddu, 0) + test_integral(QuinticHermiteSpline; args = [ddu, du, u, t], + name = "Quintic Hermite Spline (Vector) with random points") end @testset "RegularizationSmooth" begin @@ -134,9 +170,8 @@ end idx = sortperm(t) tₒ = t[idx] uₒ = u[idx] - test_integral(RegularizationSmooth, - uₒ, - tₒ; + test_integral(RegularizationSmooth; + args = [uₒ, tₒ], kwargs = [:alg => :fixed], name = "RegularizationSmooth") end diff --git a/test/interpolation_tests.jl b/test/interpolation_tests.jl index a7c4eb2e..f9ef87f8 100644 --- a/test/interpolation_tests.jl +++ b/test/interpolation_tests.jl @@ -622,6 +622,33 @@ end end end +@testset "Cubic Hermite Spline" begin + du = [-0.047, -0.058, 0.054, 0.012, -0.068, 0.0] + u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] + t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3] + A = CubicHermiteSpline(du, u, t; extrapolate = true) + @test A.(t) ≈ u + @test A(100.0)≈10.106770 rtol=1e-5 + @test A(300.0)≈9.901542 rtol=1e-5 + test_cached_index(A) + push!(u, 1.0) + @test_throws AssertionError CubicHermiteSpline(du, u, t) +end + +@testset "Quintic Hermite Spline" begin + ddu = [0.0, -0.00033, 0.0051, -0.0067, 0.0029, 0.0] + du = [-0.047, -0.058, 0.054, 0.012, -0.068, 0.0] + u = [14.7, 11.51, 10.41, 14.95, 12.24, 11.22] + t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3] + A = QuinticHermiteSpline(ddu, du, u, t; extrapolate = true) + @test A.(t) ≈ u + @test A(100.0)≈10.107996 rtol=1e-5 + @test A(300.0)≈11.364162 rtol=1e-5 + test_cached_index(A) + push!(u, 1.0) + @test_throws AssertionError QuinticHermiteSpline(ddu, du, u, t) +end + @testset "Curvefit" begin # Curvefit Interpolation rng = StableRNG(12345) diff --git a/test/parameter_tests.jl b/test/parameter_tests.jl new file mode 100644 index 00000000..3bedf3bc --- /dev/null +++ b/test/parameter_tests.jl @@ -0,0 +1,21 @@ +using DataInterpolations + +@testset "Cubic Hermite Spline" begin + du = [5.0, 3.0, 6.0, 8.0, 1.0] + u = [1.0, 5.0, 3.0, 4.0, 4.0] + t = collect(1:5) + A = CubicHermiteSpline(du, u, t) + @test A.p.c₁ ≈ [-1.0, -5.0, -5.0, -8.0] + @test A.p.c₂ ≈ [0.0, 13.0, 12.0, 9.0] +end + +@testset "Quintic Hermite Spline" begin + ddu = [0.0, 3.0, 6.0, 4.0, 5.0] + du = [5.0, 3.0, 6.0, 8.0, 1.0] + u = [1.0, 5.0, 3.0, 4.0, 4.0] + t = collect(1:5) + A = QuinticHermiteSpline(ddu, du, u, t) + @test A.p.c₁ ≈ [-1.0, -6.5, -8.0, -10.0] + @test A.p.c₂ ≈ [1.0, 19.5, 20.0, 19.0] + @test A.p.c₃ ≈ [1.5, -37.5, -37.0, -26.5] +end diff --git a/test/runtests.jl b/test/runtests.jl index a7bac9e3..01f3a07e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,6 +2,7 @@ using SafeTestsets @safetestset "Quality Assurance" include("qa.jl") @safetestset "Interface" include("interface.jl") +@safetestset "Parameter Tests" include("parameter_tests.jl") @safetestset "Interpolation Tests" include("interpolation_tests.jl") @safetestset "Derivative Tests" include("derivative_tests.jl") @safetestset "Integral Tests" include("integral_tests.jl")