This repository contains the computer implementation of the solution procedures developed in A systematic approach to obtain the analytical solution for coupled linear second-order ordinary differential equations: Part II for solving coupled systems of second order ODEs with constant coefficients
with initial conditions
and
where 
As this package is not yet registered, you must install it by using
using Pkg
Pkg.add("https://github.com/CodeLenz/Giffndof.jl.git")The OrderedDict data type of package OrderedCollections is needed to use this package. It can also be installed by using
using Pkg
Pkg.add("OrderedCollections")The following methods are exported, depending on the type of excitation:
y, yh, yp = Solve_exponential(M,C,K,U0,V0,load_data,t0=t0)y, yh, yp = Solve_polynomial(M,C,K,U0,V0,load_data,t0=t0)y, yh, yp = Solve_dirac(M,C,K,U0,V0,load_data,t0=t0)y, yh, yp = Solve_heaviside0(M,C,K,U0,V0,load_data,t0=t0)y, yh, yp = Solve_heaviside1(M,C,K,U0,V0,load_data,t0=t0)y, yh, yp = Solve_heaviside2(M,C,K,U0,V0,load_data,t0=t0)where 
y(0.1) for example.
A very efficient version is provided to compute the complete solution at a set of discrete times
response = Solve_discrete(M,C,K,times,load_data,U0,V0)where load_data::Dict{Int64, Matrix{Union{String,Float64}}} will be explained in the examples.
There is a specific way of informing non null entries in 
A,V,U,T = Solve_newmark(M::AbstractMatrix,C::AbstractMatrix,K::AbstractMatrix, f!::Function, 
                        ts::Tuple{Float64, Float64}, Δt::Float64; U0=Float64[], V0=Float64[], β=1/4, γ=1/2)where 
For forces described as a series of exponentials
the user must inform the DOF 
    load_data = Dict{Int64,Vector{ComplexF64}}()Lets consider the first example in the reference manuscript
Example
Consider a 
such that the (complex) amplitudes are 
load_data[2] = [3*im/2; -4.0*im; 0.0*im ; -3*im/2; 4.0*im; 0.0*im]The complete example is
using Giffndof
function Example_exponential(t0=0.0)
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    #----------------------------- g_2(t) = 3*sin(4 t) -----------------------------#
    # Amplitude
    ampl = 3.0
    # Angular frequency
    ws = 4.0
    # Split the ampl*sin(ws t) into two exponentials
    # with complex amplitudes
    c_21 =  ampl*im/2
    c_22 = -ampl*im/2
    # complex angular frequencies
    w_21 = -ws*im
    w_22 =  ws*im
    # and complex phases
    p_21 = 0.0*im
    p_22 = 0.0*im
    # Create a dictionary. Each key corresponds to the DOF (j)
    # such that
    # load_data[j] = [c_j1; w_j1; p_j1....; c_jnk; w_jnk; p_jnk]
    # were nk is the number of exponentials used to represent the 
    # loading at DOF j
    #
    load_data = Dict{Int64,Vector{ComplexF64}}()
    # For our example, DOF=2 and we have two exponentials
    load_data[2] = [c_21; w_21; p_21; c_22; w_22; p_22]
    # Main function -> solve the problem
    y, yh, yp = Solve_exponential(M,C,K,U0,V0,load_data,t0=t0)
    # Return the solutions for any t
    return y, yh, yp
    
 end   One can generate the visualization for 
  using Plots
  function Generate_plot(tspan = (0.0, 10.0), dt=0.01)
    # Call the example
    y, yh, yp = Example_exponential()
    # Discrete times to make the plot
    tt = tspan[1]:dt:tspan[2]
      
    # Reshape to plot
    ndofs = size(y(0.0),1)
    yy = reshape([real(y(t))[k] for k=1:ndofs for t in tt],length(tt),ndofs)
    # Plot
    display(plot(tt,yy))
end
For forces described as a polynomial
the user must inform the DOF 
    load_data = Dict{Int64,Vector{Float64}}()Example
Consider a 
such that 
load_data[2] = [0.0; 0.0; 10.0; -1.0]The complete example is
using Giffndof, OrderedCollections
function Example_polynomial(t0 = 0.0)
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    # Loading
    load_data = OrderedDict{Int64,Vector{Float64}}()
    # 10t - t^2 at DOF 2
    #        DOF     t2   c20  c21    c22  
    load_data[2] = [0.0 ; 0.0; 10.0; -1.0]
    #  Main function -> solve the problem
    y, yh, yp = Solve_polynomial(M,C,K,U0,V0,load_data,t0=t0)
    # Return the solution
    return y, yh, yp
end
One can generate the visualization for 
  using Plots  
  function Generate_plot(tspan = (0.0, 10.0), dt=0.01)
    # Call the example
    y, yh, yp = Example_polynomial()
    # Discrete times to make the plot
    tt = tspan[1]:dt:tspan[2]
      
    # Reshape to plot
    ndofs = size(y(0.0),1)
    yy = reshape([real(y(t))[k] for k=1:ndofs for t in tt],length(tt),ndofs)
    # Plot
    display(plot(tt,yy))
end
For forces described as a series of unitary impulses
the user must inform the DOF 
    load_data = Dict{Int64,Vector{Float64}}()Example
Consider a 
such that 
load_data[2] = [1.0; 1.0; -1.0; 5.0]The complete example is
using Giffndof, OrderedCollections
function Example_dirac(t0 = 0.0)
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    #
    # Loading 
    #
    # g_2(t) = delta(t-1) - delta(t-5)
    #
    load_data = OrderedDict{Int64,Vector{Float64}}()
    #
    #               c_20  t_20  c_21  t_21
    load_data[2] = [1.0 ; 1.0; -1.0 ; 5.0]
    #  Main function -> solve the problem
    y, yh, yp = Solve_dirac(M,C,K,U0,V0,load_data,t0=t0)
    # Return the solution
    return y, yh, yp
 endOne can generate the visualization for 
  using Plots
  function Generate_plot()
    # Call the example
    y, yh, yp = Example_dirac()
    # Discrete times to make the plot
    tt = tspan[1]:dt:tspan[2]
      
    # Reshape to plot
    ndofs = size(y(0.0),1)
    yy = reshape([real(y(t))[k] for k=1:ndofs for t in tt],length(tt),ndofs)
    # Plot
    display(plot(tt,yy))
end
For forces described as first order polynomials times heavisides
the user must inform the DOF 
    load_data = Dict{Int64,Vector{Float64}}()Example
Consider a 
such that 
load_data[2] = [1.0; 1.0; -1.0; 5.0]The complete example is
using Giffndof, OrderedCollections
function Example_heaviside0(t0 = 0.0)
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    #
    # Loading (1 + 0*t) H(t-1) - (1 + 0*t)H(t-5)
    #
    load_data = OrderedDict{Int64,Vector{Float64}}()
    #   c_j00  t_jk .... c_j(nk)0  t_j(nk)
    load_data[2] = [1.0; 1.0 ; -1.0;  5.0 ]
    #  Main function -> solve the problem
    y, yh, yp = Solve_heaviside0(M,C,K,U0,V0,load_data,t0=t0)
    # Return the solution
    return y, yh, yp
    
 endOne can generate the visualization for 
  using Plots  
  function Generate_plot()
    # Call the example
    y, yh, yp = Example_heaviside0()
    # Discrete times to make the plot
    tt = tspan[1]:dt:tspan[2]
      
    # Reshape to plot
    ndofs = size(y(0.0),1)
    yy = reshape([real(y(t))[k] for k=1:ndofs for t in tt],length(tt),ndofs)
    # Plot
    display(plot(tt,yy))
end
For forces described as first order polynomials times heavisides
the user must inform the DOF 
    load_data = Dict{Int64,Vector{Float64}}()Example
Consider a 
such that 
load_data[2] = [-2.0; 2.0; 1.0; 10.0; -2.0; 5.0]The complete example is
using Giffndof, OrderedCollections
function Example_heaviside1(t0 = 0.0)
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    #
    # Loading (-2+2*t) H(t-1) + (10 - 2*t)H(t-5)
    #
    load_data = OrderedDict{Int64,Vector{Float64}}()
    #   c_j00 c_j01  t_jk .... c_j(nk)0 c_j(nk)1 t_j(nk)
    load_data[2] = [-2.0; 2.0; 1.0 ; 10.0; -2.0; 5.0 ]
    #  Main function -> solve the problem
    y, yh, yp = Solve_heaviside1(M,C,K,U0,V0,load_data,t0=t0)
    # Return the solution
    return y, yh, yp
    
 endOne can generate the visualization for 
  using Plots  
  function Generate_plot()
    # Call the example
    y, yh, yp = Example_heaviside1()
    # Discrete times to make the plot
    tt = tspan[1]:dt:tspan[2]
      
    # Reshape to plot
    ndofs = size(y(0.0),1)
    yy = reshape([real(y(t))[k] for k=1:ndofs for t in tt],length(tt),ndofs)
    # Plot
    display(plot(tt,yy))
end
For forces described as second order polynomials times heavisides
the user must inform the DOF 
    load_data = Dict{Int64,Vector{Float64}}()Example
Consider a 
such that 
load_data[2] = [-30.0; 40.0; -10.0; 1.0; 30.0; -40.0; 10.0; 3.0]The complete example is
using Giffndof, OrderedCollections
function Example_heaviside2(t0 = 0.0)
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    #
    # Loading (-30 + 40*t - 10*t^2) H(t-1) + (30 - 40*t + 10*t^2)H(t-3)
    #
    load_data = OrderedDict{Int64,Vector{Float64}}()
    #   c_j00 c_j01 c_j02  t_jk .... c_j(nk)0 c_j(nk)1 c_j(nk)2 t_j(nk)
    load_data[2] = [-30.0; 40.0; -10.0; 1.0; 30.0; -40.0; 10.0; 3.0]
    
    #  Main function -> solve the problem
    y, yh, yp = Solve_heaviside2(M,C,K,U0,V0,load_data,t0=t0)
    # Return the solution
    return y, yh, yp
    
 endOne can generate the visualization for 
  using Plots  
  function Generate_plot(tspan = (0.0, 10.0), dt=0.01)
    # Call the example
    y, yh, yp = Example_heaviside2()
    # Discrete times to make the plot
    tt = tspan[1]:dt:tspan[2]
      
    # Reshape to plot
    ndofs = size(y(0.0),1)
    yy = reshape([real(y(t))[k] for k=1:ndofs for t in tt],length(tt),ndofs)
    # Plot
    display(plot(tt,yy))
end
A special method is provided if the user just wants the response 
The load dictionary is given by
    load_data::Dict{Int64, Matrix{Union{String,Float64}}}where the Int64 is the loaded DOF (key), and the string can be "sin", "cos", "dirac" or "polynomial".
The entries in the matrix depend on the type of excitation:
For "sin" and "cos" the entries are A f d where 
using Giffndof
function Example_exponential()
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    # Create the dictionary
    load_data = Dict{Int64,Matrix{Union{Float64,String}}}()
    # Apply a 3sin(4t) at the second dof    
    load_data[2] = ["sine" 3.0 (4.0/(2*pi)) 0.0]
    # Discrete times
    times = collect(range(start=0.0, stop=10.0, length=1000))
    # Evaluates the response using the Giffndof for discrete times
    response = real.(Solve_discrete(M, C, K, times, load_data, U0, V0))
    
 end   For "polynomial" the entries are [c_k t_k k] where 
using Giffndof
function Example_polynomial()
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    # Create the dictionary
    load_data = Dict{Int64,Matrix{Union{Float64,String}}}()
    # Apply the polynomial 10t - t^2, starting at t=0, to the second DOF
    load_data[2] = ["polynomial" 10.0 0.0 1.0;  
                    "polynomial" -1.0 0.0 2.0]
    # Discrete times
    times = collect(range(start=0.0, stop=10.0, length=1000))
    # Evaluates the response using the Giffndof for discrete times
    response = real.(Solve_discrete(M, C, K, times, load_data, U0, V0))
    
 end   For "dirac" the entries are [A t 0] where 
using Giffndof
function Example_dirac()
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    # Create the dictionary
    load_data = Dict{Int64,Matrix{Union{Float64,String}}}()
    # Apply TWO Dirac's delta to the second DOF. A positive at 1s and 
    # a negative at 5s.
    load_data[2] = ["dirac" 1.0 1.0 0.0; "dirac" -1.0 5.0 0.0]
    # Discrete times
    times = collect(range(start=0.0, stop=10.0, length=1000))
    # Evaluates the response using the Giffndof for discrete times
    response = real.(Solve_discrete(M, C, K, times, load_data, U0, V0))
        
 end   One is not constrained to impose a single type of excitation when using the discrete solution. For example
using Giffndof
function Example_general()
    # Mass matrix
    M = [2.0 0.0 0.0 ;
         0.0 2.0 0.0 ;
         0.0 0.0 1.0 ]
    # Stiffness matrix
    K = [6.0 -4.0  0.0 ;
        -4.0  6.0 -2.0 ;
         0.0 -2.0  6.0]*1E2
    # Damping matrix
    C = 1E-2*K
    # Initial Conditions
    U0  = [0.0; 0.0; 0.0]
    V0  = [0.0; 0.0; 0.0]
    # Create the dictionary
    load_data = Dict{Int64,Matrix{Union{Float64,String}}}()
    # Apply a Dirac's delta at 5s and a 3sin(4t) at DOF 2
    load_data[2] = ["dirac" 1.0 5.0 0.0; "sine" 3.0 (4.0/(2*pi)) 0.0 ]
    # And a -cos(5 t) at DOF 3
    load_data[3] = ["cosine" -1.0 (5.0/(2*pi)) 0.0 ]
    # Discrete times
    times = collect(range(start=0.0, stop=10.0, length=1000))
    # Evaluates the response using the Giffndof for discrete times
    response = real.(Solve_discrete(M, C, K, times, load_data, U0, V0))
        
 end   

