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
end
One 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
end
One 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
end
One 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
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_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