giffndof.jl

Generalized integrating factor for N DOFs

https://github.com/codelenz/giffndof.jl

Science Score: 44.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.4%) to scientific vocabulary
Last synced: 10 months ago · JSON representation ·

Repository

Generalized integrating factor for N DOFs

Basic Info
  • Host: GitHub
  • Owner: CodeLenz
  • License: mit
  • Language: Julia
  • Default Branch: main
  • Size: 5.18 MB
Statistics
  • Stars: 2
  • Watchers: 1
  • Forks: 1
  • Open Issues: 1
  • Releases: 0
Created about 3 years ago · Last pushed over 2 years ago
Metadata Files
Readme License Citation

README.md

Giffndof

logo

Build Status

Generalized Integrating Factor for NDOFs

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

$M A(t) + C V(t) + K Y(t) = F(t)$

with initial conditions

$Y(t_0) = U0$

and

$V(t_0) = V0$

where $t$ is the independent variable, $Y(t)$ a $n \times 1$ vector (dependent variables), $V$ its first derivative with respect to $t$ and $A$ its second derivative. Matrices $M$, $C$ and $K$ are $n \times n$. Vector $F(t)$ is informed by using a dictionary.

As this package is not yet registered, you must install it by using

julia 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

julia using Pkg Pkg.add("OrderedCollections")

The following methods are exported, depending on the type of excitation:

julia y, yh, yp = Solve_exponential(M,C,K,U0,V0,load_data,t0=t0)

julia y, yh, yp = Solve_polynomial(M,C,K,U0,V0,load_data,t0=t0)

julia y, yh, yp = Solve_dirac(M,C,K,U0,V0,load_data,t0=t0)

julia y, yh, yp = Solve_heaviside0(M,C,K,U0,V0,load_data,t0=t0)

julia y, yh, yp = Solve_heaviside1(M,C,K,U0,V0,load_data,t0=t0)

julia y, yh, yp = Solve_heaviside2(M,C,K,U0,V0,load_data,t0=t0)

where $y$ is the complete solution, $yh$ the homogeneous solution and $yp$ the permanent solution. Those solutions are functions and can be evaluated by simply passing a given time

julia y(0.1)

for example.

A very efficient version is provided to compute the complete solution at a set of discrete times

julia 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 $F(t)$ for each type of excitation. Examples to each one of the solution methods are provided in the following. Scripts to generate the plots of each example are avaliable in directory examples of this repository. A basic subroutine to compute the complete solution by using the Newmark-beta method is also provided

julia 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 $\mathbf{A}$, $\mathbf{V}$ and $\mathbf{U}$ are $n \times nt$ matrices and $nt$ is the number of time steps. $\mathbf{T}$ is a $n_t \times 1$ vector containing the discrete times. The method is used to validate the solutions of each example (dotted lines).

Exponentials

For forces described as a series of exponentials $f_j(t) = \sum_{k=1}^{n_k} c_{jk} \exp(i \omega_{jk} t + i \phi_{jk})$ the user must inform the DOF $j$ as a key to a dictionary with entries given by (possible complex values) of $c_{jk}$, $\omega_{jk}$ and $\phi_{jk}$ ```julia load_data = Dict{Int64,Vector{ComplexF64}}() ``` Lets consider the first example in the reference manuscript ## Example Consider a $3$ DOFs problem subjected to a force $f_2(t) = 3 \sin(4t) = 3\frac{i}{2}(\exp(-4it) - \exp(4it))$ such that the (complex) amplitudes are $c_{21}=3i/2$ and $c_{22}=-3i/2$, the (complex) angular frequencies are $\omega_{21}=-4i$ and $\omega_{22}=4i$ and the (complex) phases are $\phi_{21}=0$ and $\phi_{22}=0$. Thus, ```julia 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 ```julia 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 $y(t)$ ```julia 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 ```

 

Polynomials

For forces described as a polynomial $f_j(t) = \sum_{k=0}^{n_k} c_{jk} (t-t_j)^k$ the user must inform the DOF $j$ as a key to a dictionary with entries given by of $c_{jk}$ and $t_j$ ```julia load_data = Dict{Int64,Vector{Float64}}() ``` ## Example Consider a $3$ DOFs problem subjected to a force $f_2(t) = 10 t - t^2$ such that $t_2=0$, $c_{20}=0$, $c_{21}=10$, $c_{22}=-1$. Thus ```julia load_data[2] = [0.0; 0.0; 10.0; -1.0] ``` The complete example is ```julia 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 $y(t)$ ```julia 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 ```

 

Unitary impulse (Dirac's delta)

For forces described as a series of unitary impulses $f_j(t) = \sum_{k=0}^{n_k} c_{jk} \delta(t-t_{jk})$ the user must inform the DOF $j$ as a key to a dictionary with entries given by of $c_{jk}$ and $t_{jk}$ ```julia load_data = Dict{Int64,Vector{Float64}}() ``` ## Example Consider a $3$ DOFs problem subjected to two oposite unitary impulses at $t=1$ and $t=5$ s $f_2(t) = \delta(t-1) - \delta(t-5)$ such that $c_{20}=1.0$, $t_{20}=1$, $c_{21}=-1$ and $t_{21}=5.0$ ```julia load_data[2] = [1.0; 1.0; -1.0; 5.0] ``` The complete example is ```julia 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 $y(t)$ ```julia 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 ```

 

Zero order polynomials multiplied by Heavisides

For forces described as first order polynomials times heavisides $f_j(t) = \sum_{k=0}^{n_k} (c_{jk0}) H(t-t_{jk})$ the user must inform the DOF $j$ as a key to a dictionary with entries given by of $c_{jk*}$ and $t_{jk}$ ```julia load_data = Dict{Int64,Vector{Float64}}() ``` ## Example Consider a $3$ DOFs problem subjected to two oposite unitary steps at $t=1$ and $t=5$ s $f_2(t) = H(t-1) - H(t-5)$ such that $c_{200}=1$, $t_{20}=1$, $c_{210}=-1$, $t_{21}=5$ ```julia load_data[2] = [1.0; 1.0; -1.0; 5.0] ``` The complete example is ```julia 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 $y(t)$ ```julia 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 ```

 

First order polynomials multiplied by Heavisides

For forces described as first order polynomials times heavisides $f_j(t) = \sum_{k=0}^{n_k} (c_{jk0} + c_{jk1} t ) H(t-t_{jk})$ the user must inform the DOF $j$ as a key to a dictionary with entries given by of $c_{jk*}$ and $t_{jk}$ ```julia load_data = Dict{Int64,Vector{Float64}}() ``` ## Example Consider a $3$ DOFs problem subjected to a linear ramp from $t=1$ to $t=5$ s and a constant value for $t>=5$. $f_2(t) = (-2+2t)*H(t-1) + (10-2t)*H(t-5)$ ![linear](docs/images/linear.png) such that $c_{200}=-2$, $c_{201}=2$, $t_{20}=1$, $c_{210}=10$, $c_{211}=-2$, $t_{21}=5$ ```julia load_data[2] = [-2.0; 2.0; 1.0; 10.0; -2.0; 5.0] ``` The complete example is ```julia 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 $y(t)$ ```julia 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 ```

 

Second order polynomials multiplied by Heavisides

For forces described as second order polynomials times heavisides $f_j(t) = \sum_{k=0}^{n_k} (c_{jk0} + c_{jk1} t + c_{jk2} t^2) H(t-t_{jk})$ the user must inform the DOF $j$ as a key to a dictionary with entries given by of $c_{jk*}$ and $t_{jk}$ ```julia load_data = Dict{Int64,Vector{Float64}}() ``` ## Example Consider a $3$ DOFs problem subjected a "bump" between $t=1$ and $t=3$ s and zero elsewere. $f_2(t) = (-30 + 40t - 10t^2)H(t-1) + (30 - 40t + 10t^2)H(t-3)$ ![quadratic](docs/images/quadratic.png) such that $c_{200}=-30$, $c_{201}=40$, $c_{202}=-10$, $t_{20}=1$, $c_{210}=30$, $c_{211}=-40$, $c_{212}=10$, $t_{21}=3$ ```julia load_data[2] = [-30.0; 40.0; -10.0; 1.0; 30.0; -40.0; 10.0; 3.0] ``` The complete example is ```julia 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 $y(t)$ ```julia 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 ```

 

Efficient Discrete solution

A special method is provided if the user just wants the response $\mathbf{y}$ at a discrete set of times. The user can specify different types of loading at the same time using a dictionary and mix exponentials, polynomials and Dirac's deltas at the same time. There are substancial differences when compared to the previous methods. The load dictionary is given by ```julia 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 $A$ is an amplitude, $f$ is a frequency in Hz and $d$ is a phase in degrees. ```julia 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 $k=0$ for the constant term, $k=1$ for the linear term and so on. ```julia 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 $A$ is an amplitude and $t$ is the activation time. The last position is not used. ```julia 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 ```julia 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 ```

Owner

  • Name: Eduardo Lenz
  • Login: CodeLenz
  • Kind: user
  • Location: Joinville, Brazil
  • Company: UDESC

Citation (CITATION.cff)

# This CITATION.cff file was generated with cffinit.
# Visit https://bit.ly/cffinit to generate yours today!

cff-version: 1.2.0
title: Giffndof
message: >-
  If you use this software, please cite it using the
  metadata from this file.
type: software
authors:
  - given-names: Eduardo
    family-names: Lenz Cardoso
    email: eduardo.cardoso@udesc.br
    orcid: 'https://orcid.org/0000-0002-3634-3916'
    affiliation: UDESC
  - given-names: Matheus
    family-names: Janczkowski Fogaça
    email: matheusj2009@hotmail.com
    affiliation: UDESC
    orcid: 'https://orcid.org/0000-0003-4513-0290'
identifiers:
  - type: url
    value: 'https://github.com/CodeLenz/Giffndof.jl'
repository-code: 'https://github.com/CodeLenz/Giffndof.jl'
url: 'https://github.com/CodeLenz/Giffndof.jl'
abstract: >-
  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
license: MIT

GitHub Events

Total
Last Year