In [1]:
using PtFEM, DataFrames, Plots


INFO: Recompiling stale cache file /Users/rob/.julia/lib/v0.5/DataTables.ji for module DataTables.
WARNING: Method definition describe(AbstractArray) in module StatsBase at /Users/rob/.julia/v0.5/StatsBase/src/scalarstats.jl:573 overwritten in module DataTables at /Users/rob/.julia/v0.5/DataTables/src/abstractdatatable/abstractdatatable.jl:381.
WARNING: Method definition describe(AbstractArray) in module StatsBase at /Users/rob/.julia/v0.5/StatsBase/src/scalarstats.jl:573 overwritten in module DataFrames at /Users/rob/.julia/v0.5/DataFrames/src/abstractdataframe/abstractdataframe.jl:407.
WARNING: Method definition describe(AbstractArray) in module DataTables at /Users/rob/.julia/v0.5/DataTables/src/abstractdatatable/abstractdatatable.jl:381 overwritten in module DataFrames at /Users/rob/.julia/v0.5/DataFrames/src/abstractdataframe/abstractdataframe.jl:407.
WARNING: Method definition describe(Any, AbstractArray{#T<:Number, N<:Any}) in module DataTables at /Users/rob/.julia/v0.5/DataTables/src/abstractdatatable/abstractdatatable.jl:383 overwritten in module DataFrames at /Users/rob/.julia/v0.5/DataFrames/src/abstractdataframe/abstractdataframe.jl:409.
WARNING: Method definition describe(Any, AbstractArray{#T<:Any, N<:Any}) in module DataTables at /Users/rob/.julia/v0.5/DataTables/src/abstractdatatable/abstractdatatable.jl:400 overwritten in module DataFrames at /Users/rob/.julia/v0.5/DataFrames/src/abstractdataframe/abstractdataframe.jl:426.
WARNING: Method definition append!(NullableArrays.NullableArray{WeakRefStrings.WeakRefString{#T<:Any}, 1}, NullableArrays.NullableArray{WeakRefStrings.WeakRefString{#T<:Any}, 1}) in module Data at /Users/rob/.julia/v0.5/DataStreams/src/DataStreams.jl:344 overwritten in module DataTables at /Users/rob/.julia/v0.5/DataTables/src/abstractdatatable/io.jl:318.
WARNING: Method definition describe(AbstractArray) in module StatsBase at /Users/rob/.julia/v0.5/StatsBase/src/scalarstats.jl:573 overwritten in module DataFrames at /Users/rob/.julia/v0.5/DataFrames/src/abstractdataframe/abstractdataframe.jl:407.
WARNING: Method definition append!(NullableArrays.NullableArray{WeakRefStrings.WeakRefString{#T<:Any}, 1}, NullableArrays.NullableArray{WeakRefStrings.WeakRefString{#T<:Any}, 1}) in module Data at /Users/rob/.julia/v0.5/DataStreams/src/DataStreams.jl:344 overwritten in module DataTables at /Users/rob/.julia/v0.5/DataTables/src/abstractdatatable/io.jl:318.
INFO: Recompiling stale cache file /Users/rob/.julia/lib/v0.5/OffsetArrays.ji for module OffsetArrays.
INFO: Recompiling stale cache file /Users/rob/.julia/lib/v0.5/Plots.ji for module Plots.
INFO: Recompiling stale cache file /Users/rob/.julia/lib/v0.5/GR.ji for module GR.
INFO: Recompiling stale cache file /Users/rob/.julia/lib/v0.5/WriteVTK.ji for module WriteVTK.
INFO: Recompiling stale cache file /Users/rob/.julia/lib/v0.5/Codecs.ji for module Codecs.
WARNING: using Plots.GR in module Main conflicts with an existing identifier.

PtFEM.jl contains the Julia version of the Fortran toolkit as described in the book "Programming the Finite Element Method" ("PtFEM") by I. M. Smith, D. V. Griffiths & L. Margetts (5th edition).

The Julia DataFrames package is used to display the final results. The Julia Plots package is used to plot the results, in this notebook using the GR backend. See https://juliaplots.github.io

Currently in PtFEM, the examples in PtFEM consists of 3 Julia components:

  1. The input data, e.g. for the example defined in p4.1.1.jl. In this tutorial notebook the contents of p4.1.1 is re-created. The p4.1.1.jl Julia file itself can be found in the "examples/4 Static Equilibrium" subdirectory of the PtFEM.jl package.

  2. A program skeleton as described in the PtFEM book, e.g. Program 4.1 is p4_1.jl in subdirectory "src/Chap04" and can be included accordingly (see below).

  3. The skeleton programs call the appropriate Julia functions in subdirectory "src/PtFEM".


In [2]:
path = joinpath(Pkg.dir("PtFEM"), "src", "Chap04")
# If p4_1 already loaded, skip the include.
if !isdefined(Main, :p4_1)
    include(path*"/p4_1.jl")
end


could not open file /Users/rob/.julia/v0.5/PtFEM/src/Chap04/p4_1.jl

 in include_from_node1(::String) at ./loading.jl:488
 in include_from_node1(::String) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?

Thus this tutorial notebook consists of 2 parts:

1. Show how to create the contents of Ex4.1.1.jl and use this as input to the included p4_1.jl function.

2. Step by step explanation what happens in p4_1.

Note: p4_1.jl, the skeleton program used in this example, is an almost straight translation from Fortran in PtFEM to Julia in PtFEM.jl (with the exception of the program input and output sections). This is true for all px_x.jl files.

Define the structural element type and the finite element used to create a mesh over the structural element.


In [3]:
struct_el = :Rod   # A 1-dimensional structural element that can only handle axial forces.
fin_el = :Line     # The type of finite element used to construct a mesh for the structural element;

Define the overall parameters


In [4]:
l = 1.0       # Total length of structural element [m]
q = 5.0       # Distributed load [N/m]
N = 10        # Number of nodes
els = N - 1   # Number of finite elements
nod = 2       # Number of nodes per finite elements
nodof = 1     # Degrees of freedom for each node, just axial ;

Create input dictionary


In [5]:
data = Dict(
  # Rod(nxe, np_types, nip, fin_el(nod, nodof))
  :struc_el => getfield(Main, Symbol(struct_el))(els, 1, 1,
    getfield(Main, Symbol(fin_el))(nod, nodof)),
  :properties => [1.0e5;],
  :x_coords => 0.0:l/els:l,
  :support => [(N, [0])],
  :loaded_nodes => [(i, repeat([0.0], inner=nodof)) for i in 1:N],
  :eq_nodal_forces_and_moments => [(i, repeat([0.0], inner=nodof*nod)) for i in 1:els]
);

In this example there are only distributed loads. Otherwise set data[:loaded_nodes] to the external forces and moments directly applied to nodes, e.g.:

data[:loaded_nodes][2] = (2, [5.0])

Assign the distributed load contribution to nodal forces


In [6]:
for node in 1:els
  data[:eq_nodal_forces_and_moments][node][2][1] = (1/2)*q*l/els
  data[:eq_nodal_forces_and_moments][node][2][2] = (1/2)*q*l/els
end

Add the equivalent distributed forces and moment to existing loaded_nodes entry in data.


In [7]:
for node in 1:N-1
  data[:loaded_nodes][node][2][1] += data[:eq_nodal_forces_and_moments][node][2][1]
  data[:loaded_nodes][node+1][2][1] += data[:eq_nodal_forces_and_moments][node][2][2]
end

In [8]:
data


Out[8]:
Dict{Symbol,Any} with 6 entries:
  :eq_nodal_forces_and_moments => Tuple{Int64,Array{Float64,1}}[(1,[0.277778,0.…
  :support                     => Tuple{Int64,Array{Int64,1}}[(10,[0])]
  :struc_el                    => PtFEM.Rod(9,1,1,PtFEM.Line(2,1))
  :properties                  => [100000.0]
  :x_coords                    => 0.0:0.1111111111111111:1.0
  :loaded_nodes                => Tuple{Int64,Array{Float64,1}}[(1,[0.277778]),…

Notice that in this 'flagpole' example the x axis goes from top to bottom and the distributed load is compressive. The clamped ('encastré') end node is node N.

Now call the p4.1 skeleton


In [9]:
m = p4_1(data);


UndefVarError: p4_1 not defined

In [10]:
@time m = p4_1(data);


UndefVarError: p4_1 not defined

In [11]:
m.displacements


UndefVarError: m not defined

Internal element actions, not correctred for applied equivalent nodal forces and moments, this will be done below


In [12]:
m.actions


UndefVarError: m not defined

Reconstruct stiffness matrix from skyline vector


In [13]:
full(sparse(m.cfgsm))


UndefVarError: m not defined

Create the result dataframes.

Dataframe dis_df holds the node displacements (deflections and rotations).

Dataframe fm_df holds the element actions (forces and moments).


In [14]:
dis_df = DataFrame(
x_deflections = m.displacements[:, 1],
)

fm_df = DataFrame(
    normal_force_1 = m.actions[:, 1],
    normal_force_2 = m.actions[:, 2],
);


UndefVarError: m not defined

Correct element forces and moments for equivalent nodal forces and moments introduced for loading between nodes


In [15]:
if :eq_nodal_forces_and_moments in keys(data)
    eqfm = data[:eq_nodal_forces_and_moments]
    k = data[:struc_el].fin_el.nod * data[:struc_el].fin_el.nodof
    for t in eqfm
      for i in 1:k
            fm_df[t[1], i] -= round(t[2][i], 2)
      end
    end
end


UndefVarError: fm_df not defined

 in macro expansion; at ./In[15]:6 [inlined]
 in anonymous at ./<missing>:?

In [16]:
dis_df


UndefVarError: dis_df not defined

In [17]:
fm_df


UndefVarError: fm_df not defined

In [18]:
gr(size=(400,600))


Out[18]:
Plots.GRBackend()

In [19]:
p = Vector{Plots.Plot{Plots.GRBackend}}(2)
titles = ["EEM fig 1.1 u(x)", "EEM fig 1.1 N(x)"]
fors = vcat(fm_df[:, :normal_force_1], q*l);


UndefVarError: fm_df not defined

In [20]:
p[1] = plot(data[:x_coords], -fors,
    xlim=(0,l), ylim=(-6.0, 0.0),
    xlabel="x [m]", ylabel="Normal force [N]", color=:blue,
    line=(:dash,1), marker=(:dot,1,0.8,stroke(1,:black)),
    title=titles[2], leg=false
);


UndefVarError: fors not defined

In [21]:
p[2] = plot(data[:x_coords], m.displacements[:, 1],
    xlim=(0, l), ylim=(0.0, 0.00003),
    xlabel="x [m]", ylabel="Deflection [m]", color=:red,
    line=(:dash,1), marker=(:circle,1,0.8,stroke(1,:black)),
    title=titles[1], leg=false
);


UndefVarError: m not defined

In [22]:
plot(p..., layout=(2, 1))


UndefRefError: access to undefined reference

In [ ]: