diff --git a/src/DormandPrince.jl b/src/DormandPrince.jl index 18cd925..909b1fc 100644 --- a/src/DormandPrince.jl +++ b/src/DormandPrince.jl @@ -10,6 +10,7 @@ include("checks.jl") include("interface.jl") include("dp5/mod.jl") include("dp8/mod.jl") +include("show.jl") # export Interface export AbstractDPSolver, diff --git a/src/interface.jl b/src/interface.jl index 229ba0c..b1e809d 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -35,7 +35,7 @@ integrate_core!(::AbstractDPSolver{T}, ::T) where T = error("not implemented") function integrate!(solver::AbstractDPSolver{T}, time::T) where T <: Real report = integrate_core!(solver, time) if report.idid != COMPUTATION_SUCCESSFUL - error("integration failed at time $time with report $report") + throw(DPException(report)) end end function integrate!(callback, solver::AbstractDPSolver{T}, times::AbstractVector{T}; sort_times::Bool = true) where {T <: Real} diff --git a/src/show.jl b/src/show.jl new file mode 100644 index 0000000..fa12001 --- /dev/null +++ b/src/show.jl @@ -0,0 +1,103 @@ +function Base.show(io::IO, mime::MIME"text/plain", solver::DP5Solver) + tab(n) = " "^(n + get(io, :indent, 0)) + + printstyled(io, tab(0), "DP5Solver Object", color=:underline) + println(io, tab(0), "\n") + + print(io, tab(0), "Current x: ") + printstyled(io, solver.vars.x, "\n", color=:blue) + print(io, tab(0), "Current y: ") + printstyled(io, solver.y, "\n", color=:green) + + println(io, tab(0), "") + + show(io, mime, solver.options) +end + + +function Base.show(io::IO, mime::MIME"text/plain", solver::DP8Solver) + tab(n) = " "^(n + get(io, :indent, 0)) + + printstyled(io, tab(0), "DP8Solver Object", color=:underline) + println(io, tab(0), "\n") + + print(io, tab(0), "Current x: ") + printstyled(io, solver.vars.x, "\n", color=:blue) + print(io, tab(0), "Current y: ") + printstyled(io, solver.y, "\n", color=:green) + + println(io, tab(0), "") + + show(io, mime, solver.options) +end + + +function Base.show(io::IO, ::MIME"text/plain", options::Options) + + tab(n) = " "^(n + get(io, :indent, 0)) + println(io, tab(0), "Options: ") + + print(io, tab(4), "Absolute Tolerance: ") + printstyled(io, options.atol, "\n", color=:light_magenta) + print(io, tab(4), "Relative Tolerance: ") + printstyled(io, options.rtol, "\n", color=:light_magenta) + + print(io, tab(4), "uround: ") + printstyled(io, options.uround, "\n", color=:light_magenta) + print(io, tab(4), "Safety Factor: ") + printstyled(io, options.safety_factor, "\n", color=:light_magenta) + print(io, tab(4), "Step Size Selection 1: ") + printstyled(io, options.step_size_selection_one, "\n", color=:light_magenta) + print(io, tab(4), "Step Size Selection 2: ") + printstyled(io, options.step_size_selection_two, "\n", color=:light_magenta) + print(io, tab(4), "β: ") + printstyled(io, options.beta, "\n", color=:light_magenta) + print(io, tab(4), "Maximal step size: ") + printstyled(io, options.maximal_step_size, "\n", color=:light_magenta) + print(io, tab(4), "Initial Step Size: ") + printstyled(io, options.initial_step_size, "\n", color=:light_magenta) + print(io , tab(4), "Maximum Allowed Steps: ") + printstyled(io, options.maximum_allowed_steps, "\n", color=:light_magenta) + print(io, tab(4), "Print Error Messages: ") + printstyled(io, options.print_error_messages, "\n", color=:light_magenta) + print(io, tab(4), "Stiffness Test Activation Step: ") + printstyled(io, options.stiffness_test_activation_step, "\n", color=:light_magenta) + + +end + +function Base.show(io::IO, ::MIME"text/plain", report::Report) + tab(n) = " "^(n + get(io, :indent, 0)) + printstyled(io, tab(0), "Integration Report", color=:underline) + println(io, tab(0), "\n") + + print(io, tab(4), "Stopped at x: ") + printstyled(io, report.x_final, "\n", color=:blue) + + print(io, tab(4), "checks: ") + if report.checks == INPUT_CHECKS_SUCCESSFUL + printstyled(io, report.checks, "\n", color=:green) + else + printstyled(io, report.checks, "\n", color=:red) + end + + print(io, tab(4), "idid: ") + if report.idid == COMPUTATION_SUCCESSFUL + printstyled(io, report.idid, "\n", color=:green) + else + printstyled(io, report.idid, "\n", color=:red) + end + + print(io, tab(4), "Function Evaluations: ") + printstyled(io, report.num_func_evals, "\n", color=:light_magenta) + print(io, tab(4), "Computed Steps: ") + printstyled(io, report.num_computed_steps, "\n", color=:light_magenta) + print(io, tab(4), "Accepted Steps: ") + printstyled(io, report.num_accepted_steps, "\n", color=:green) + print(io, tab(4), "Rejected Steps: ") + printstyled(io, report.num_rejected_steps, "\n", color=:red) +end + +function Base.showerror(io::IO, e::DPException) + show(io, MIME"text/plain"(), e.report) +end \ No newline at end of file diff --git a/src/types.jl b/src/types.jl index 6eda7dc..bd19e1a 100644 --- a/src/types.jl +++ b/src/types.jl @@ -28,6 +28,10 @@ struct Report{T <: Real} num_rejected_steps::Int end +struct DPException <: Exception + report::Report +end + @option struct Options{T <: Real} # originally in work[1] - work[7] uround::T = eps(T) diff --git a/test/interface.jl b/test/interface.jl index d4f57cb..ea15a46 100644 --- a/test/interface.jl +++ b/test/interface.jl @@ -108,4 +108,17 @@ end @test callback_times == times end end + + @testset "integrate! exception" begin + solver = DP5Solver( + fcn, + 0.0, + ComplexF64[1.0, 0.0] + ; + maximum_allowed_steps=10 + + ) + + @test_throws DormandPrince.DPException integrate!(solver, 2π) + end end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index d2b2742..a8100c3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -18,4 +18,8 @@ end @testset "Error Paths" begin include("errors.jl") +end + +@testset "Pretty Printing" begin + include("show.jl") end \ No newline at end of file diff --git a/test/show.jl b/test/show.jl new file mode 100644 index 0000000..c44ed6f --- /dev/null +++ b/test/show.jl @@ -0,0 +1,77 @@ +# show solver and report + +using DormandPrince +using Test + +function stiff_fcn(x, y, f) + f[1] = y[1]^2 - y[1]^3 +end + +@testset "DP8 Solver" begin + solver = DP8Solver( + stiff_fcn, + 0.0, + [0.0001] + ) + + show(stdout, MIME"text/plain"(), solver) +end + +@testset "Successful Options Check with Successful Integration" begin + solver = DP5Solver( + stiff_fcn, + 0.0, + [0.0001] + ) + + show(stdout, MIME"text/plain"(), solver) + + report = DormandPrince.integrate_core!(solver, 2/0.0001) + + show(stdout, MIME"text/plain"(), report) + +end + +@testset "Successful Options Check with Failed Integration" begin + solver = DP5Solver( + stiff_fcn, + 0.0, + [0.0001]; + maximum_allowed_steps=10 + ) + + report = DormandPrince.integrate_core!(solver, 2/0.0001) + + show(stdout, MIME"text/plain"(), report) +end + +@testset "Failed Options Check" begin + solver = DP5Solver( + stiff_fcn, + 0.0, + [0.0001]; + uround = 100 + ) + + report = DormandPrince.integrate_core!(solver, 2/0.0001) + + show(stdout, MIME"text/plain"(), report) + +end + +@testset "DPException" begin + + # generate a healthy report but encapsulate it inside a DPException + + solver = DP5Solver( + stiff_fcn, + 0.0, + [0.0001] + ) + + report = DormandPrince.integrate_core!(solver, 2/0.0001) + + dp_exception = DormandPrince.DPException(report) + + showerror(stdout, dp_exception) +end \ No newline at end of file