Static analysis of a beam

Cantilever bend, with out-of-plane load leading to a three-dimensional response mobilizing axial force, bending moment and torque. Comparison to solutions by Longva (2015) and Crisfield (1990)

using Muscade, StaticArrays, GLMakie
include("BeamElements.jl");


R = 100.0;  # Radius of the bend [m]
EI₂ = 833.33e3;  # Bending stiffness [Nm²]
EI₃ = 833.33e3;  # Bending stiffness [Nm²]
EA = 1e9;  # Axial stiffness [N]
GJ = 705e3;  # Torsional stiffness [Nm²]

Create the model

nel         = 8
nnodes      = nel+1
nodeCoord   = hcat( 0 .+ R*cos.(3π/2 .+ ((1:nnodes).-1)/(nnodes-1)*π/4),
                    0 .+ zeros(Float64,nnodes,1),
                    R .+ R*sin.(3π/2 .+ ((1:nnodes).-1)/(nnodes-1)*π/4))
mat         = BeamCrossSection(EA=EA,EI₂=EI₂,EI₃=EI₃,GJ=GJ,μ=1.,ι₁=1.)
model       = Model(:TestModel)
nodid       = addnode!(model,nodeCoord)
mesh        = hcat(nodid[1:nnodes-1],nodid[2:nnodes])
eleid       = addelement!(model,EulerBeam3D,mesh;mat=mat,orient2=SVector(0.,1.,0.))
[addelement!(model,Hold,[nodid[1]]  ;field) for field∈[:t1,:t2,:t3,:r1,:r2,:r3]]; # Clamp at one end

Define the loading procedure. First 300 N then 450 and 600 N

function load(t)
    t<=1. ? load=t*300. :
    t>1. && t<=2. ? load=300. +(t-1)*150. :
    load=450. +(t-2)*150.
end
addelement!(model,DofLoad,[nodid[nnodes]];field=:t2,value=t->load(t));                                        # Force along axis2 at other

Run the static analysis

initialstate    = initialize!(model);
loadSteps = [0.,1.,2.,3.];
nLoadSteps = length(loadSteps)
state           = solve(SweepX{0};initialstate,time=loadSteps,verbose=true,maxΔx=1e-9);



Muscade: SweepX{0} solver

    step   1 converged in   1 iterations. |Δx|=5.0e-15 |Lλ|=7.7e-07
    step   2 converged in  11 iterations. |Δx|=2.3e-12 |Lλ|=7.1e-07
    step   3 converged in   8 iterations. |Δx|=2.4e-11 |Lλ|=1.6e-06
    step   4 converged in   8 iterations. |Δx|=1.4e-11 |Lλ|=1.4e-06

    nel=15, ndof=60, nstep=4, niter=28, niter/nstep= 7.00
    SweepX{0} time:   12 [s]
Muscade done.

Fetch and show beam profile for all load cases

x_ = [getdof(state[idxLoad];field=:t1,nodID=nodid[1:nnodes]) for idxLoad ∈ 1:nLoadSteps]
y_ = [getdof(state[idxLoad];field=:t2,nodID=nodid[1:nnodes]) for idxLoad ∈ 1:nLoadSteps]
z_ = [getdof(state[idxLoad];field=:t3,nodID=nodid[1:nnodes]) for idxLoad ∈ 1:nLoadSteps]

fig      = Figure(size = (1000,1000))
ax = Axis3(fig[1,1],xlabel="x [m]", ylabel="y [m]", zlabel="z [m]",aspect=:equal)
for idxLoad ∈ 1:nLoadSteps
    lines!(ax,nodeCoord[:,1]+x_[idxLoad][:], nodeCoord[:,2]+y_[idxLoad][:] , nodeCoord[:,3]+z_[idxLoad][:]                  , label="F="*string(load(loadSteps[idxLoad]))*" N");
end
xlims!(ax, 0,70); ylims!(ax, 0,60); zlims!(ax, 0,40); axislegend()
currentDir = @__DIR__
if occursin("build", currentDir)
    save(normpath(joinpath(currentDir,"..","src","assets","StaticBeamAnalysis1.png")),fig)
elseif occursin("examples", currentDir)
    save(normpath(joinpath(currentDir,"StaticBeamAnalysis1.png")),fig)
end

Result

Fetch and display results at the Gauss points for the last load case

idxLoad = 4;

Location of the 4 Gauss points

xgp1 = (1. /nel)*( (0.5-1/2*sqrt(3/7+2/7*sqrt(6/5))) :1:nel)
xgp2 = (1. /nel)*( (0.5-1/2*sqrt(3/7-2/7*sqrt(6/5))) :1:nel)
xgp3 = (1. /nel)*( (0.5+1/2*sqrt(3/7-2/7*sqrt(6/5))) :1:nel)
xgp4 = (1. /nel)*( (0.5+1/2*sqrt(3/7+2/7*sqrt(6/5))) :1:nel)
xgps = [xgp1;xgp2;xgp3;xgp4];

Axial force

req = @request gp(resultants(fᵢ))
out = getresult(state[idxLoad],req,eleid)
Fgp1_ = [ out[idxEl].gp[1][:resultants][:fᵢ] for idxEl ∈ 1:nel]
Fgp2_ = [ out[idxEl].gp[2][:resultants][:fᵢ] for idxEl ∈ 1:nel]
Fgp3_ = [ out[idxEl].gp[3][:resultants][:fᵢ] for idxEl ∈ 1:nel]
Fgp4_ = [ out[idxEl].gp[4][:resultants][:fᵢ] for idxEl ∈ 1:nel];

Bending moments

req = @request gp(resultants(mᵢ))
out = getresult(state[idxLoad],req,eleid)
Mgp1_ = [ out[idxEl].gp[1][:resultants][:mᵢ] for idxEl ∈ 1:nel]
Mgp2_ = [ out[idxEl].gp[2][:resultants][:mᵢ] for idxEl ∈ 1:nel]
Mgp3_ = [ out[idxEl].gp[3][:resultants][:mᵢ] for idxEl ∈ 1:nel]
Mgp4_ = [ out[idxEl].gp[4][:resultants][:mᵢ] for idxEl ∈ 1:nel];

Strains

req = @request ε
out = getresult(state[idxLoad],req,eleid)
εgp1_ = [ out[idxEl].ε[1] for idxEl ∈ 1:nel]
εgp2_ = [ out[idxEl].ε[1] for idxEl ∈ 1:nel];
εgp3_ = [ out[idxEl].ε[1] for idxEl ∈ 1:nel];
εgp4_ = [ out[idxEl].ε[1] for idxEl ∈ 1:nel];

Curvatures

req = @request gp(κ)
out = getresult(state[idxLoad],req,eleid)
κgp1_ = [ out[idxEl].gp[1].κ[1] for idxEl ∈ 1:nel]
κgp2_ = [ out[idxEl].gp[2].κ[1] for idxEl ∈ 1:nel]
κgp3_ = [ out[idxEl].gp[3].κ[1] for idxEl ∈ 1:nel]
κgp4_ = [ out[idxEl].gp[4].κ[1] for idxEl ∈ 1:nel];

Plot strains, etc. at Gauss points

fig      = Figure(size = (1000,1000))
ax=Axis(fig[1,1], ylabel="Forces F [N]",       yminorgridvisible = true,xminorgridvisible = true,xticks = (0:1. /nel:1))
scatter!(ax,xgps,  [[Fgp1_[iel][1] for iel=1:nel] ; [Fgp2_[iel][1] for iel=1:nel] ; [Fgp3_[iel][1] for iel=1:nel] ; [Fgp4_[iel][1] for iel=1:nel]],          label="F₁");
ax.title = "Internal loads, elongation and curvature at last load step"
axislegend();
ax=Axis(fig[2,1], ylabel="Strain [-]",       yminorgridvisible = true,xminorgridvisible = true,xticks = (0:1. /nel:1))
scatter!(ax,xgps,  [[εgp1_[iel][1] for iel=1:nel] ; [εgp2_[iel][1] for iel=1:nel] ; [εgp3_[iel][1] for iel=1:nel] ; [εgp4_[iel][1] for iel=1:nel]],          label="ε");
ax=Axis(fig[3,1], ylabel="Moments M [Nm]",       yminorgridvisible = true,xminorgridvisible = true,xticks = (0:1. /nel:1))
scatter!(ax,xgps,  [[Mgp1_[iel][1] for iel=1:nel] ; [Mgp2_[iel][1] for iel=1:nel] ; [Mgp3_[iel][1] for iel=1:nel] ; [Mgp4_[iel][1] for iel=1:nel]],          label="M₁");
scatter!(ax,xgps,  [[Mgp1_[iel][2] for iel=1:nel] ; [Mgp2_[iel][2] for iel=1:nel] ; [Mgp3_[iel][2] for iel=1:nel] ; [Mgp4_[iel][2] for iel=1:nel]],          label="M₂");
scatter!(ax,xgps,  [[Mgp1_[iel][3] for iel=1:nel] ; [Mgp2_[iel][3] for iel=1:nel] ; [Mgp3_[iel][3] for iel=1:nel] ; [Mgp4_[iel][3] for iel=1:nel]],          label="M₃");
axislegend()
ax=Axis(fig[4,1], ylabel="Curvature κ [m⁻¹]",       yminorgridvisible = true,xminorgridvisible = true,xticks = (0:1. /nel:1),xlabel="Position along beam / beam length [-]")
scatter!(ax,xgps,  [[κgp1_[iel][1] for iel=1:nel] ; [κgp2_[iel][1] for iel=1:nel] ; [κgp3_[iel][1] for iel=1:nel] ; [κgp4_[iel][1] for iel=1:nel]],          label="κ₁");
scatter!(ax,xgps,  [[κgp1_[iel][2] for iel=1:nel] ; [κgp2_[iel][2] for iel=1:nel] ; [κgp3_[iel][2] for iel=1:nel] ; [κgp4_[iel][2] for iel=1:nel]],          label="κ₂");
scatter!(ax,xgps,  [[κgp1_[iel][3] for iel=1:nel] ; [κgp2_[iel][3] for iel=1:nel] ; [κgp3_[iel][3] for iel=1:nel] ; [κgp4_[iel][3] for iel=1:nel]],          label="κ₃");
axislegend()
if occursin("build", currentDir)
    save(normpath(joinpath(currentDir,"..","src","assets","StaticBeamAnalysis2.png")),fig)
elseif occursin("examples", currentDir)
    save(normpath(joinpath(currentDir,"StaticBeamAnalysis2.png")),fig)
end

Result

Show comparison with solutions by Longva (2015) and Crisfield (1990)

# Load                300 N                       450 N                       600 N
#                     x,y,z                       x,y,z                       x,y,z
# Disp Longva         58.56, 40.47, 22.18         51.99, 48.72, 18.45         46.91, 53.64, 15.65
# Disp Crisfield      58.53, 40.53, 22.16         51.93, 48.79, 18.43         46.84, 53.71, 15.61
height = [  nodeCoord[end,1]+x_[2][end], 58.56, 58.53, nodeCoord[end,1]+x_[3][end], 51.99, 51.93, nodeCoord[end,1]+x_[4][end], 46.91, 46.84,
            nodeCoord[end,2]+y_[2][end], 40.47, 40.53, nodeCoord[end,2]+y_[3][end], 48.72, 48.79, nodeCoord[end,2]+y_[4][end], 53.64, 53.71,
            nodeCoord[end,3]+z_[2][end], 22.18, 22.16, nodeCoord[end,3]+z_[3][end], 18.45, 18.43, nodeCoord[end,3]+z_[4][end], 15.65, 15.61]
colors = [:red, :blue, :green]
tbl = (cat = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9],height,
       grp = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3])
fig = Figure(size = (2000, 400))
ax = Axis(fig[1,1], xticks = (1:9, ["x @ 300 N", "x @ 450 N", "x @ 600 N", "y @ 300 N", "y @ 450 N", "y @ 600 N", "z @ 300 N", "z @ 450 N", "z @ 600 N"]),
                    ylabel = "End node coordinate [m]")
barplot!(ax, tbl.cat, tbl.height,
        dodge = tbl.grp,
        color = colors[tbl.grp],
        bar_labels = :y
        )
ylims!(ax, 0,70);
labels = ["Muscade", "Longva (2015)", "Crisfield (1990)"]
elements = [PolyElement(polycolor = colors[i]) for i in 1:length(labels)]
title = "Method"
Legend(fig[1,2], elements, labels, title)
if occursin("build", currentDir)
    save(normpath(joinpath(currentDir,"..","src","assets","StaticBeamAnalysis3.png")),fig)
elseif occursin("examples", currentDir)
    save(normpath(joinpath(currentDir,"StaticBeamAnalysis3.png")),fig)
end

Result


This page was generated using Literate.jl.