using TriShellFiniteElement
using Ferrite
function create_cook_grid(nx, ny)
corners = [Tensors.Vec{2}((0.0, 0.0)),
Tensors.Vec{2}((48.0, 44.0)),
Tensors.Vec{2}((48.0, 60.0)),
Tensors.Vec{2}((0.0, 44.0))]
return generate_grid(Triangle, (nx, ny), corners)
end
# integrate the traction force
function traction_force_vector!(cell, fv, traction)
fe = zeros(length(cell.dofs))
for facet in 1:nfacets(cell)
if (cellid(cell), facet) ∈ getfacetset(grid, "traction")
reinit!(fv, cell, facet)
for q_point in 1:getnquadpoints(fv)
dΓ = getdetJdV(fv, q_point)
for i in 1:getnbasefunctions(fv)
Nᵢ = shape_value(fv, q_point, i)
# @show i, Nᵢ, traction, dΓ
fe[i] += (Nᵢ ⋅ traction) * dΓ
end
end
end
end
return fe
end
# explicit assembly of the stiffness and force vector
function assemble_shell!(K, F, dh, qr1, qr3, ip3, ip6, E, ν, t, traction)
assembler = start_assemble(K, F)
for cell in CellIterator(dh)
x = getcoordinates(cell)
ke = TriShellFiniteElement.elastic_stiffness_matrix!(qr1, qr3, ip3, ip6, E, ν, t, x)
fe = traction_force_vector!(cell, fv, traction)
assemble!(assembler, celldofs(cell), ke, fe)
end
return K, F
end
# Grid, dofhandler, boundary condition
n = 50
grid = create_cook_grid(n, n)
# facesets for boundary conditions
addfacetset!(grid, "clamped", x -> x[1] ≈ 0.0)
addfacetset!(grid, "traction", x -> x[1] ≈ 48.0)
# interpolation order
ip = Lagrange{RefTriangle,1}() #to define fields only
#TODO can be swapped
ip3 = TriShellFiniteElement.IP3()
ip6 = TriShellFiniteElement.IP6()
# ip3 = Lagrange{RefTriangle,1}()
# ip6 = Lagrange{RefTriangle,2}()
qr1 = QuadratureRule{RefTriangle}(1)
qr3 = QuadratureRule{RefTriangle}(2)
facet_qr = FacetQuadratureRule{RefTriangle}(1)
# cell and face value for u
cv = CellValues(qr1, ip3, ip3)
fv = FacetValues(facet_qr, ip^3)
# degrees of freedom for displacements and rotations
dh = DofHandler(grid)
add!(dh, :u, ip^3)
add!(dh, :θ, ip^2)
close!(dh)
# boundary conditions
dbc = ConstraintHandler(dh)
add!(dbc, Dirichlet(:u, getfacetset(dh.grid, "clamped"), x -> zero(x), [1, 2]))
add!(dbc, Dirichlet(:θ, getfacetset(dh.grid, "clamped"), x -> zero(x), [1, 2]))
close!(dbc)
# material properties
E = 0.7 # 70 Pa in N/dm^2
t = 0.5
ν = 0.3333
# Assembly and solve
Ke = allocate_matrix(dh)
f = zeros(ndofs(dh))
# point evaluation
ph = PointEvalHandler(grid, [Tensors.Vec{2}((48.0, 60.0))])
# traction vector in units N/dm/thickness
traction = Tensors.Vec((0.0, 1/16*t, 0.0))
# assemble the system
Ke, f = assemble_shell!(Ke, f, dh, qr1, qr3, ip3, ip6, E, ν, t, traction)
# apply the BCs
apply!(Ke, f, dbc)
# solve
@time u = Ke \ f
# evaluate point value
u_eval = first(evaluate_at_points(ph, dh, u, :u))
@show u_eval
@show ip3, ip6
VTKGridFile("mindlin_shell", dh) do vtk
write_solution(vtk, dh, u)
end
@cristophermoen
I've been through the source code of this package and of
Ferrite.jland I've got a few questions. I'll put them here as it might be useful to keep track of those.I've noticed that the
IP3()andIP6()ScalarInterpolationare very similar to theLagrange{RefTriangle, order}from FerriteThe only difference that I could find is that there is a switch in the node numbering, which means that the shape functions are swapped.
The same goes for the
IP6()andLagrange{RefTriangle, 2}.I've tested it on a Cook's membrane case, and I get identical results if I swap them for Ferrite's internal ones
This leads to the two following questions
ScalarInterpolationfrom Ferrite?IP3()works since we have a 3D displacement field which would requireIP3()^3or similar? I guess this crashes due to some internal assumption in theCellValues?CooksMembrane.jl script?