view test/SimpleTimeSteppers/SimpleTimeSteppers_test.jl @ 862:a382942e5437 feature/subpackage_simple_timesteppers

Add a few simple timesteppers
author Jonatan Werpers <jonatan@werpers.com>
date Tue, 18 Jan 2022 15:29:54 +0100
parents
children
line wrap: on
line source

using Test
using Sbplib.SimpleTimeSteppers


@testset "rk4" begin
    ode_solutions = @NamedTuple{F,v}.([
        ((v,t) ->  0., (v₀,t₀,t) -> v₀),
        ((v,t) ->  1., (v₀,t₀,t) -> v₀+t-t₀),
        ((v,t) ->   t, (v₀,t₀,t) -> v₀+(t^2-t₀^2)/2),
        ((v,t) ->   v, (v₀,t₀,t) -> v₀*exp(t-t₀)),
        ((v,t) -> t*v, (v₀,t₀,t) -> v₀*exp((t^2-t₀^2)/2)),
    ])

    @testset "Exact" begin
        @testset for i ∈ eachindex(ode_solutions[1:3])
            F, v = ode_solutions[i]
            cases = @NamedTuple{v₀,t₀}.([
                (0.,0.),
                (0.,1.),
                (1.,0.),
                (1.,1.),
                (2.,0.),
                (0.,2.),
                (2.,2.),
            ])

            @testset for (v₀,t₀) ∈ cases
                @testset for Δt ∈ [0., 1., .5, 2.]
                    @test rk4(F, v₀, t₀, Δt) == v(v₀, t₀, t₀+Δt)
                end
            end
        end
    end

    @testset "Approximate" begin
        @testset for i ∈ eachindex(ode_solutions)
            F, v = ode_solutions[i]

            @testset for v₀ ∈ [1., .5] ,t₀ ∈ [0., 1.]
                Δt = 0.1
                @test rk4(F, v₀, t₀, Δt) ≈ v(v₀, t₀, t₀+Δt) rtol=1e-6
            end
        end
    end
end

@testset "rkn4" begin

    function damped_oscillator(v₀, v̇₀,t₀,t; ζ)
        ω = sqrt(1-ζ^2)

        C = v̇₀ + ζ*v₀

        V = v₀*cos(ω*(t-t₀)) + C*sin(ω*(t-t₀))
        V̇ = C*cos(ω*(t-t₀)) - v₀*sin(ω*(t-t₀))
        v =    exp(-ζ*(t-t₀))*V
        v̇ = -ζ*exp(-ζ*(t-t₀))*V + exp(-ζ*(t-t₀))*V̇
        return v, v̇
    end

    ode_solutions = @NamedTuple{F,vv̇}.([
        ((v,v̇,t) ->  0.,       (v₀,v̇₀,t₀,t) -> (v₀ + (t-t₀)*v̇₀,                 v̇₀)),
        ((v,v̇,t) ->  1.,       (v₀,v̇₀,t₀,t) -> (v₀ + (t-t₀)*v̇₀ + (t-t₀)^2/2,    v̇₀ + t - t₀)),
        ((v,v̇,t) ->   t,       (v₀,v̇₀,t₀,t) -> (v₀ + (t-t₀)*v̇₀ + (t-t₀)^3/6+ t₀/2*(t-t₀)^2,  v̇₀ + (t^2-t₀^2)/2)),
        ((v,v̇,t) ->  -v,       (v₀,v̇₀,t₀,t) -> (v₀*cos(t-t₀) + v̇₀*sin(t-t₀),   v̇₀*cos(t-t₀) - v₀*sin(t-t₀))),
        ((v,v̇,t) ->  -v-6/5*v̇, (v₀,v̇₀,t₀,t) -> damped_oscillator(v₀,v̇₀,t₀,t; ζ=3/5)),
    ])

    @testset "Exact" begin
        @testset for i ∈ eachindex(ode_solutions[1:3])
            F, vv̇ = ode_solutions[i]
            @testset for v₀ ∈ [0., 1., 2.], v̇₀ ∈ [0., 1.], t₀ ∈ [0.,1.,2.]
                @testset for Δt ∈ [0., 1., .5, 2.]
                    V,V̇ = rkn4(F, v₀, v̇₀, t₀, Δt)
                    v,v̇ = vv̇(v₀, v̇₀, t₀, t₀+Δt)
                    @test V ≈ v rtol=1e-15
                    @test V̇ ≈ v̇ rtol=1e-15
                end
            end
        end
    end

    @testset "Approximate" begin
        @testset for i ∈ eachindex(ode_solutions)
            F, vv̇ = ode_solutions[i]
            @testset for v̇₀ ∈ [0., 0.5], v₀ ∈ [1., 0.5], t₀∈[0.,1.]
                Δt = 0.1
                V,V̇ = rkn4(F, v₀, v̇₀, t₀, Δt)
                v,v̇ = vv̇(v₀, v̇₀, t₀, t₀+Δt)

                if i != 5
                    @test V ≈ v rtol=1e-6
                    @test V̇ ≈ v̇ rtol=1e-6
                else
                    # TODO: Is this a bug or reasonable?
                    @test_broken V ≈ v rtol=1e-6
                    @test_broken V̇ ≈ v̇ rtol=1e-6
                end
            end
        end
    end
end

@testset "cdiff" begin
    ode_solutions = @NamedTuple{F,vv̇}.([
        ((v,t) ->  0., (v₀,v̇₀,t₀,t) -> v₀ + (t-t₀)*v̇₀),
        ((v,t) ->  1., (v₀,v̇₀,t₀,t) -> v₀ + (t-t₀)*v̇₀ + (t-t₀)^2/2),
        ((v,t) ->   t, (v₀,v̇₀,t₀,t) -> v₀ + (t-t₀)*v̇₀ + (t-t₀)^3/6+ t₀/2*(t-t₀)^2),
        ((v,t) ->  -v, (v₀,v̇₀,t₀,t) -> v₀*cos(t-t₀) + v̇₀*sin(t-t₀)),
    ])

    @testset "Exact" begin
        @testset for i ∈ eachindex(ode_solutions[1:3])
            F, v = ode_solutions[i]
            @testset for v₀ ∈ [1., 2.], v̇₀ ∈ [0., 1.], t₀ ∈ [0.,1.,2.]
                @testset for Δt ∈ [0., 1., .5]
                    v₋₁ = v(v₀, v̇₀, t₀, t₀-Δt)
                    v₁  = v(v₀, v̇₀, t₀, t₀+Δt)

                    V₁, V₀ = centered_2nd_order_fd(F, v₀, v₋₁, t₀, Δt)

                    @test V₁ ≈ v₁ rtol=1e-15
                    @test V₀ ≈ v₀ rtol=1e-15
                end
            end
        end
    end

    @testset "Approximate" begin
        @testset for i ∈ eachindex(ode_solutions)
            F, v = ode_solutions[i]
            @testset for v̇₀ ∈ [0., 0.5], v₀ ∈ [1., 0.5], t₀ ∈ [0.,1.]
                Δt = 0.1
                v₋₁ = v(v₀, v̇₀, t₀, t₀-Δt)
                v₁  = v(v₀, v̇₀, t₀, t₀+Δt)

                V₁, V₀ = centered_2nd_order_fd(F, v₀, v₋₁, t₀, Δt)


                @test V₁ ≈ v₁ rtol=1e-5
                @test V₀ ≈ v₀ rtol=1e-5
            end
        end
    end
end