Raw File
SimpleShooting.jl
# This file implements some Shooting Methods to locate periodic orbits
# The code is quite unstable so I would favour instead PeriodicOrbitFD

####################################################################################################
# Periodic Orbits via implicit midpoint method, order 2 in time
@with_kw struct ShootingProblemMid{vectype, S <: LinearSolver, N} <: PeriodicOrbit
    # Function F(x, p) = 0
    F::Function

    # Jacobian of F wrt x
    J::Function

    # variables to define a Poincare Section
    ϕ::vectype
    xπ::vectype

    # discretisation of the time interval
    M::Int = 100

    linsolve::S
    options_newton::NewtonPar{N}
end

function (poPb::ShootingProblemMid{vectype, S, N})(u0::vectype) where {vectype, S, N}
    T = u0[end]
    u = @view u0[1:end-1]
    # discretisation of the time interval [0, T]
    h = T / poPb.M

    Fper = (u, u0)-> (u .- u0) .- h .* poPb.F((u.+u0)./2)
    dFper = (u, u0) -> I - h * poPb.J((u.+u0)./2)/2

    x0 = copy(u)
    xnew  = Flow(Fper, dFper, x0, poPb.M, poPb.options_newton)
    return vcat(xnew - u, dot(poPb.ϕ, u - poPb.xπ))
end

struct PeriodicOrbitLinearSolverMid <: LinearSolver

end

function (ls::PeriodicOrbitLinearSolverMid)(Jper, rhs)
    @assert 1==0 "Very unstable Implementation"
    printstyled(color=:green, "*"^50*"\n--> Linsolve periodic orbit\n")

    # parameters extraction
    x = Jper[1][1:end-1]     #the jacobian is evaluated at
    T = Jper[1][end]
    @show N, T
    poPb = Jper[2]
    M = poPb.M

    Fper = (u, u0)-> (u .- u0) .- h .* poPb.F((u+u0)./2)
    dFper =    (u, u0) ->  I - h * poPb.J((u+u0)/2)/2
    dFperInv = (u, u0) -> -I - h * poPb.J((u+u0)/2)/2


    # the Jacobian of the functional for periodic orbits is [J -F((uM+uM-1)/2)/M;dg 0]
    dg = poPb.ϕ

    # if I write xi the sequence of time slice in the Backward Euler scheme, we find
    # (I - h⋅J(S)/2)⋅∂xi+1/∂x0 = (I + h⋅J(S)/2)⋅∂xi/∂x0 with S = (xi+1 + xi)/2 hence:
    # ∂xi+1/∂x0 = A(S)⋅∂xi/∂x0 where A(xi) = (I - h⋅J(S)/2)^{-1}(I + h⋅J(S)/2)
    # Hence Jper x = A(xm) A(xm-1)⋯A(x0)x
    # We want to solve the linear system Jper * x = rhs, it follows that
    # x = A(x0)\A(x1)\⋯A(xM)\rhs with
    # A(xi) \ rhs = (I + h⋅J(S)/2)^{-1}(I - h⋅J(S)/2)⋅rhs = (I - 2(I + h⋅J(S)/2)J(S))⋅rhs

    # discretisation of the time interval [0, T]
    h = T / poPb.M
    δ = 1e-9
    dTFper = (poPb(vcat(x, T+δ)) - poPb(Jper[1])) / δ

    # we solve the equations to find F(xM)
    x0 = copy(x)
    xM = copy(x)
    xhist = [x]
    for ii=1:poPb.M
        xM, _, flag = newtonGMRES(u->Fper(u, x0), u->dFper(u, x0), x0, poPb.options_newton)
        @assert flag == true "Newton did not converge at i = $ii"
        x0 .= xM
        push!(xhist, xM)
    end

    # the Jacobian of the functional for periodic orbits is [J dTFper;dg 0]
    # we want to solve J⋅out + dF z = h = rhs[1:N]. We compute x1 = J\h and x2 = J\dF and out = x1 - z*x2
    # with (dg, out) = (dg, x1) - z (dg, x2) = rhs[N+1]
    x1 = copy(rhs[1:end-1])
    x2 = copy(dTFper[1:end-1])
    # here we start from xM and compute xM-1 and use this to inverse Jper


    for ii=poPb.M+1:-1:2
        PO1 = xhist[ii]
        PO0 = xhist[ii-1]

        S = (PO1 .+ PO0) / 2

        # jacobian at S
        J = h/2 * poPb.J(S)

        # @show norm(J, Inf64)
        # @error "semble instable"
        # x1 .= x1 .- 2(I+J) \ (J*x1)
        # x2 .= x2 .- 2(I+J) \ (J*x2)
        # @show norm(inv(I+J), Inf64) norm((J), Inf64)
        x1 .= (I + J) \ (x1 .- J * x1)
        x2 .= (I + J) \ (x2 .- J * x2)

        # PO1 .= PO0
    end
    @show norm(x1, Inf64), length(xhist)

    @show rhs[end] dot(dg, x1) dot(dg, x2)
    # we can now solve the bordered system
    z = (dot(dg, x1) - rhs[end]) / (dot(dg, x2))
    @show z
    @show norm(x1, Inf64) norm(x2, Inf64)
    @show norm(x1 - z * x2, Inf64)

    printstyled(color=:green, "----> end\n")
    # @assert 1==0
    return vcat(x1 - z * x2, z), true, 1
end

####################################################################################################
####################################################################################################
# other functional for searching for Periodic Orbits with Trapezoidal rule, order 2 in time

@with_kw struct ShootingProblemTrap{vectype, S <: LinearSolver, N} <: PeriodicOrbit
    # Function F(x, p) = 0
    F::Function

    # Jacobian of F wrt x
    J::Function

    # variables to define a Poincare Section
    ϕ::vectype
    xπ::vectype

    #discretisation of the time interval
    M::Int = 100

    linsolve::S
    options_newton::NewtonPar{N}
end

function (poPb::ShootingProblemTrap{vectype, S, N})(u0::vectype) where {vectype, S, N}
    T = u0[end]
    u = @view u0[1:end-1]
    # discretisation of the time interval [0, T]
    h = T / poPb.M
    # we solve M times the Backward Euler scheme
    Fper = (u, u0)-> (u .- u0) .- h .* (poPb.F(u) .+ poPb.F(u0)) / 2
    dFper = (u, u0) -> I - h * poPb.J(u) / 2

    x0 = copy(u)
    xnew  = Flow(Fper, dFper, x0, poPb.M, poPb.options_newton)
    return vcat(x0 - u, dot(x0 - poPb.xπ, poPb.ϕ))
end

####################################################################################################
####################################################################################################
# other functional for searching for Periodic Orbits based on Backward Euler Scheme

@with_kw struct ShootingProblemBE{vectype, S <: LinearSolver, N} <: PeriodicOrbit
    # Function F(x, p) = 0
    F::Function

    # Jacobian of F wrt x
    J::Function

    # variables to define a Poincare Section
    ϕ::vectype
    xπ::vectype

    #discretisation of the time interval
    M::Int = 100

    linsolve::S
    options_newton::NewtonPar{N}
end

function (poPb::ShootingProblemBE{vectype, S, N})(u0::vectype) where {vectype, S, N}
    T = u0[end]
    u = @view u0[1:end-1]
    # discretisation of the time interval [0, T]
    h = T / poPb.M
    # we solve M times the Backward Euler scheme
    Fper = (u, u0)-> (u .- u0) .- h .* poPb.F(u)
    dFper = (u, u0) -> I - h * poPb.J(u)

    x0 = copy(u)
    xnew  = Flow(Fper, dFper, x0, poPb.M, poPb.options_newton)
    return vcat(x0 - u, dot(x0 - poPb.xπ, poPb.ϕ))
end
back to top