diff --git a/README.md b/README.md index 7965fb6..fd1b9c3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # DormandPrince.jl +[![codecov](https://codecov.io/github/QuEraComputing/DormandPrince.jl/graph/badge.svg?token=qYZ4V7m0JY)](https://codecov.io/github/QuEraComputing/DormandPrince.jl) + Julia-native implementation of the Dormand-Prince 5th order solver ## Installation diff --git a/test/checks.jl b/test/checks.jl new file mode 100644 index 0000000..179ce2a --- /dev/null +++ b/test/checks.jl @@ -0,0 +1,49 @@ +using Test +using DormandPrince.DP5Core: + DP5Options, + check_max_allowed_steps, + check_uround, + check_beta, + check_safety_factor + +@testset "Test Checks" begin + + @testset "Check Max Allowed Steps" begin + options = DP5Options{Float64}(maximum_allowed_steps=-1) + @test check_max_allowed_steps(options) == false + + options = DP5Options{Float64}(maximum_allowed_steps=1) + @test check_max_allowed_steps(options) == true + end + + @testset "Check uround" begin + options = DP5Options{Float64}(uround=1e-36) + @test check_uround(options) == false + + options = DP5Options{Float64}(uround=1.1) + @test check_uround(options) == false + + options = DP5Options{Float64}(uround=1e-10) + @test check_uround(options) == true + end + + @testset "Check beta" begin + options = DP5Options{Float64}(beta=0.3) + @test check_beta(options) == false + + options = DP5Options{Float64}(beta=0.01) + @test check_beta(options) == true + end + + @testset "Check safety factor" begin + options = DP5Options{Float64}(safety_factor=1.1) + @test check_safety_factor(options) == false + + options = DP5Options{Float64}(safety_factor=1e-5) + @test check_safety_factor(options) == false + + options = DP5Options{Float64}(safety_factor=0.5) + @test check_safety_factor(options) == true + end + +end diff --git a/test/errors.jl b/test/errors.jl new file mode 100644 index 0000000..642c2be --- /dev/null +++ b/test/errors.jl @@ -0,0 +1,38 @@ +using Test +using DormandPrince.DP5Core: + DP5Solver, + DP5Options, + LARGER_NMAX_NEEDED, + STEP_SIZE_BECOMES_TOO_SMALL, + dopcor + +function fcn(x, y, f) + f[1] = y[1]^2 - y[1]^3 +end + +@testset "Larger nmax needed" begin + solver = DP5Solver( + fcn, + 0.0, # start at 0.0 + [0.0001] # delta + ; maximum_allowed_steps=1 + ) + + + h, report = dopcor(solver, 2/0.0001, 0.1, 0.0) + @test report.idid == LARGER_NMAX_NEEDED + +end + +@testset "Step size becomes too small" begin + solver = DP5Solver( + fcn, + 0.0, + [0.0001] + ; uround=10000 + ) + + + h, report = dopcor(solver, 2/0.0001, 0.1, 0.0) + @test report.idid == STEP_SIZE_BECOMES_TOO_SMALL +end diff --git a/test/exact_evol_helpers.jl b/test/exact_evol_helpers.jl deleted file mode 100644 index c92f5a5..0000000 --- a/test/exact_evol_helpers.jl +++ /dev/null @@ -1,16 +0,0 @@ -function evolution_operator(t::Float64) - ϕ = 2.2 * sin(π * t)^2 - U = zeros(ComplexF64, 2,2) - U[1,1] = 1 / sqrt(2) - U[2,1] = 1 / sqrt(2) - U[2,2] = 1 / sqrt(2) - U[1,2] = -1 / sqrt(2) - - U * diagm(exp.([-im*ϕ, im*ϕ])) * U' -end - -function solution(t) - U = evolution_operator(t) - return U * [1.0, 0.0] - -end \ No newline at end of file diff --git a/test/interface.jl b/test/interface.jl new file mode 100644 index 0000000..fe1fb20 --- /dev/null +++ b/test/interface.jl @@ -0,0 +1,97 @@ +using Test +using LinearAlgebra +using DormandPrince: DP5Solver, integrate + +function evolution_operator(t::Float64) + ϕ = 2.2 * sin(π * t)^2 + U = zeros(ComplexF64, 2,2) + U[1,1] = 1 / sqrt(2) + U[2,1] = 1 / sqrt(2) + U[2,2] = 1 / sqrt(2) + U[1,2] = -1 / sqrt(2) + + U * diagm(exp.([-im*ϕ, im*ϕ])) * U' +end + +function solution(t) + U = evolution_operator(t) + return U * [1.0, 0.0] + +end + +function fcn(x, y, f) + g(x) = 2.2*2π*sin(2π*x) + + f[1] = -1im * g(x)/2 * y[2] + f[2] = -1im * g(x)/2 * y[1] +end + +# standalone solver test +@testset "Integration Test" begin + solver = DP5Solver( + fcn, + 0.0, + ComplexF64[1.0, 0.0] + ) + + integrate(solver, 2π) + + @test solver.y ≈ solution(2π) +end + +# Test integrate() +@testset "Integration Interface Test" begin + + # test iterator generation + @testset "Iterator Interface" begin + times = [0.1, 0.5, 1.1] + exact_values = [] + dp5_values = [] + + # get exact values + for t in times + push!(exact_values, solution(t)) + end + + # use iterator to get exact values + solver = DP5Solver( + fcn, + 0.0, + ComplexF64[1.0, 0.0] + ) + + iter = integrate(solver, times) + + for (t,y) in iter + push!(dp5_values, copy(y)) + end + + @test dp5_values ≈ exact_values + end + + @testset "Callback Interface" begin + times = [0.1, 0.5, 1.1] + callback_times = [] + exact_values = [] + dp5_values = [] + + # get exact values + for t in times + push!(exact_values, solution(t)) + end + + # use iterator to get exact values + solver = DP5Solver( + fcn, + 0.0, + ComplexF64[1.0, 0.0] + ) + + integrate(solver, times) do t, y + push!(callback_times, t) + push!(dp5_values, copy(y)) + end + + @test dp5_values ≈ exact_values + end +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index bc91a95..d2b2742 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,86 +1,21 @@ -using Test -using LinearAlgebra -using DormandPrince: DP5Solver, dopri5, integrate -# test error paths of dopcor, bypass checks if necessary - -include("exact_evol_helpers.jl") +# test error paths of dopcor, bypass checks if necessary -function fcn(x, y, f) - g(x) = 2.2*2π*sin(2π*x) +using Test - f[1] = -1im * g(x)/2 * y[2] - f[2] = -1im * g(x)/2 * y[1] +@testset "Interface" begin + include("interface.jl") end -# standalone solver test -@testset "Integration Test" begin - solver = DP5Solver( - fcn, - 0.0, - ComplexF64[1.0, 0.0] - ) - - integrate(solver, 2π) - - @test solver.y ≈ solution(2π) +@testset "Checks" begin + include("checks.jl") end -# Test integrate() -@testset "Integration Interface Test" begin - - # test iterator generation - @testset "Iterator Interface" begin - times = [0.1, 0.5, 1.1] - exact_values = [] - dp5_values = [] - - # get exact values - for t in times - push!(exact_values, solution(t)) - end - # use iterator to get exact values - solver = DP5Solver( - fcn, - 0.0, - ComplexF64[1.0, 0.0] - ) - - iter = integrate(solver, times) - - for (t,y) in iter - push!(dp5_values, copy(y)) - end - - @test dp5_values ≈ exact_values - end - - @testset "Callback Interface" begin - times = [0.1, 0.5, 1.1] - callback_times = [] - exact_values = [] - dp5_values = [] - - # get exact values - for t in times - push!(exact_values, solution(t)) - end - - # use iterator to get exact values - solver = DP5Solver( - fcn, - 0.0, - ComplexF64[1.0, 0.0] - ) - - integrate(solver, times) do t, y - push!(callback_times, t) - push!(dp5_values, copy(y)) - end - - @test dp5_values ≈ exact_values - end +@testset "Stiff ODE" begin + include("stiff.jl") end - +@testset "Error Paths" begin + include("errors.jl") +end \ No newline at end of file diff --git a/test/stiff.jl b/test/stiff.jl new file mode 100644 index 0000000..c9ce6a6 --- /dev/null +++ b/test/stiff.jl @@ -0,0 +1,18 @@ +using Test +using DormandPrince: DP5Solver, integrate + +function fcn(x, y, f) + f[1] = y[1]^2 - y[1]^3 +end + +@testset "Stiff ODE" begin + + solver = DP5Solver( + fcn, + 0.0, # start at 0.0 + [0.0001] # initial value of delta + ) + + integrate(solver, 2/0.0001) + +end