Beam under on/off loading: transient response

December 23, 2023 · View on GitHub

Source code: beam_load_on_off_tut.jl

Description

A cantilever beam is loaded by a trapezoidal-pulse traction load at its free cross-section. The load is applied within 0.015 seconds and taken off after 0.37 seconds. The beam oscillates about its equilibrium configuration.

The beam is modeled as a solid. Trapezoidal rule is used to integrate the equations of motion in time. Rayleigh mass- and stiffness-proportional damping is incorporated. The dynamic stiffness is factorized for efficiency.

Goals

  • Show how to create the discrete model, with implicit dynamics and proportional damping.
  • Apply distributed loading varying in time.
  • Demonstrate trapezoidal-rule time stepping.
#

Definitions

Basic imports.

using LinearAlgebra
using Arpack

This is the finite element toolkit itself.

using FinEtools
using FinEtools.AlgoBaseModule: matrix_blocked, vector_blocked

The linear stress analysis application is implemented in this package.

using FinEtoolsDeforLinear
using FinEtoolsDeforLinear.AlgoDeforLinearModule

Input parameters

E = 205000*phun("MPa");# Young's modulus
nu = 0.3;# Poisson ratio
rho = 7850*phun("KG*M^-3");# mass density
loss_tangent = 0.005;
L = 200*phun("mm");
W = 4*phun("mm");
H = 8*phun("mm");
tolerance = W/500;
qmagn = 0.1*phun("MPa");
tend = 0.5*phun("SEC");


#

Create the discrete model

MR = DeforModelRed3D
fens,fes  = H8block(L, W, H, 50, 2, 4)

geom = NodalField(fens.xyz)
u = NodalField(zeros(size(fens.xyz,1),3)) # displacement field

nl = selectnode(fens, box=[L L -Inf Inf -Inf Inf], inflate=tolerance)
setebc!(u, nl, true, 1)
setebc!(u, nl, true, 2)
setebc!(u, nl, true, 3)
applyebc!(u)
numberdofs!(u)

corner = selectnode(fens, nearestto=[0 0 0])
cornerzdof = u.dofnums[corner[1], 3]

material = MatDeforElastIso(MR, rho, E, nu, 0.0)

femm = FEMMDeforLinearMSH8(MR, IntegDomain(fes, GaussRule(3,2)), material)
femm = associategeometry!(femm, geom)
K = stiffness(femm, geom, u)
femm = FEMMDeforLinear(MR, IntegDomain(fes, GaussRule(3,3)), material)
M = mass(femm, geom, u)

Extract the free-free block of the matrices.

M_ff = matrix_blocked(M, nfreedofs(u))[:ff]
K_ff = matrix_blocked(K, nfreedofs(u))[:ff]

Find the boundary finite elements at the tip cross-section of the beam. The uniform distributed loading will be applied to these elements.

bdryfes = meshboundary(fes)

Those facing in the positive X direction will be chosen:

tipbfl = selectelem(fens, bdryfes, facing=true, direction=[-1.0 0.0 0.0])

A base finite element model machine will be created to evaluate the loading. The force intensity is created as driven by a function, but the function really only just fills the buffer with the constant loading vector.

function pfun(forceout::Vector{T}, XYZ, tangents, feid, qpid) where {T}
    forceout .=  [0.0, 0.0, qmagn]
    return forceout
end
fi = ForceIntensity(Float64, 3, pfun);

The loading vector is lumped from the distributed uniform loading by integrating on the boundary. Hence, the dimension of the integration domain is 2.

el1femm =  FEMMBase(IntegDomain(subset(bdryfes,tipbfl), GaussRule(2,2)))
F = distribloads(el1femm, geom, u, fi, 2);
F_f, F_d = vector_blocked(F, nfreedofs(u))[(:f, :d)]

The loading function is defined as a time -dependent multiplier of the constant distribution of the loading on the structure.

function tmult(t)
    if (t <= 0.015)
        t/0.015
    else
        if (t >= 0.4)
            0.0
        else
            if (t <= 0.385)
                1.0
            else
                (t - 0.4)/(0.385 - 0.4)
            end
        end
    end
end


#

Time step determination

We figure out the fundamental mode frequency, which will determine the time step is a fraction of the period.

evals, evecs = eigs(K_ff, M_ff; nev=1, which=:SM);

The fundamental angular frequency is then:

omega_f = real(sqrt(evals[1]));

We take the time step to be a fraction of the period of vibration in the fundamental mode.

@show dt = 0.05 * 1/(omega_f/2/pi);


#

Damping model

We take the damping to be representative of what's happening at the fundamental vibration frequency.

For a given loss factor at a certain frequency ωf\omega_f, the stiffness-proportional damping coefficient may be estimated as 2loss_tangent/ωf\omega_f, and the mass-proportional damping coefficient may be estimated as 2loss_tangent*ωf\omega_f.

Rayleigh_mass = (loss_tangent/2)*omega_f;
Rayleigh_stiffness = (loss_tangent/2)/omega_f;

Now we construct the Rayleigh damping matrix as a linear combination of the stiffness and mass matrices.

C_ff = Rayleigh_stiffness * K_ff + Rayleigh_mass * M_ff

The time stepping loop is protected by let end to avoid unpleasant surprises with variables getting clobbered by globals.

ts, corneruzs = let dt = dt, F_f = F_f

Initial displacement, velocity, and acceleration.

    U0 = gathersysvec(u)
    v = deepcopy(u)
    V0 = gathersysvec(v)
    U1 = fill(0.0, length(V0))
    V1 = fill(0.0, length(V0))
    F0 = deepcopy(F_f)
    F1 = fill(0.0, length(F0))
    R  = fill(0.0, length(F0))

Factorize the dynamic stiffness

    DSF = cholesky((M_ff + (dt/2)*C_ff + ((dt/2)^2)*K_ff))

The times and displacements of the corner will be collected into two vectors

    ts = Float64[]
    corneruzs = Float64[]

Let us begin the time integration loop:

    t = 0.0;
    step = 0;
    F0 .= tmult(t) .* F_f
    while t < tend
        push!(ts, t)
        push!(corneruzs, U0[cornerzdof])
        t = t+dt;
        step = step + 1;
        (mod(step,100)==0) && println("Step $(step): $(t)")

Set the time-dependent load

        F1 .= tmult(t) .* F_f

Compute the out of balance force.

        R .= (M_ff*V0 - C_ff*(dt/2*V0) - K_ff*((dt/2)^2*V0 + dt*U0) + (dt/2)*(F0+F1));

Calculate the new velocities.

        V1 = DSF\R;

Update the velocities.

        U1 = U0 + (dt/2)*(V0+V1);

Switch the temporary vectors for the next step.

        U0, U1 = U1, U0;
        V0, V1 = V1, V0;
        F0, F1 = F1, F0;
        if (t == tend) # Are we done yet?
            break;
        end
        if (t+dt > tend) # Adjust the last time step so that we exactly reach tend
            dt = tend-t;
        end
    end
    ts, corneruzs # return the collected results
end

#

Plot the results

using Gnuplot

@gp "set terminal windows 0 " :-
@gp  :- ts corneruzs./phun("mm") "lw 2 lc rgb 'red' with lines title 'Displacement of the corner' "
@gp  :- "set xlabel 'Time [s]'"
@gp  :- "set ylabel 'Displacement [mm]'"

The end.

true

This page was generated using Literate.jl.