Shells and Mindlin Plates
Overview
A plate is a flat structural element loaded transversely (out of its plane); a shell is its curved or membrane-coupled generalization. Where the thin-plate (Kirchhoff–Love) model in the plates tutorial neglects transverse shear, the Mindlin–Reissner model keeps it, so it stays accurate for thicker plates. A flat shell is a Mindlin plate fused with a membrane element, so it carries in-plane (stretch) and out-of-plane (bend) loads at once.
Rasmah provides mindlin_plate_stiffness / solve_mindlin_plate and flat_shell_stiffness / solve_flat_shell (each with a solve(MindlinPlate(), …) / solve(FlatShell(), …) physics wrapper). The Mindlin plate is verified against the closed-form sinusoidal-load solution.
A structured plate mesh
Both elements live on a TriangleMesh. Build a structured grid of the unit square:
using Rasmah
using LinearAlgebra
function square_tri(n)
xs = range(0.0, 1.0; length = n)
v = Matrix{Float64}(undef, 2, n * n)
k = 0
for j in 1:n, i in 1:n
k += 1; v[1, k] = xs[i]; v[2, k] = xs[j]
end
f = Matrix{Int}(undef, 3, 2 * (n - 1)^2)
k = 0
for j in 1:(n - 1), i in 1:(n - 1)
a = (j - 1) * n + i; b = a + 1; c = a + n; d = c + 1
k += 1; f[:, k] = [a, b, c]
k += 1; f[:, k] = [b, d, c]
end
TriangleMesh(v, f)
end
plate = square_tri(16)
println(size(plate.vertices, 2), " vertices, ", size(plate.faces, 2), " triangles")256 vertices, 450 triangles
Each node carries three dofs (w, θₓ, θ_y) — the transverse deflection and the two rotations — numbered (3i-2, 3i-1, 3i).
Mindlin plate vs. the exact solution
For a simply-supported square plate under a sinusoidal load q = q₀ sin(πx) sin(πy), the exact Mindlin centre deflection is w = 1/(4π⁴D) + 1/(2π² κ G t) (Reddy), where D = E t³/(12(1−ν²)) is the flexural rigidity. The first term is the Kirchhoff (thin-plate) deflection; the second is the shear correction the Mindlin model adds:
E, ν, t, κ, q0 = 1e7, 0.3, 0.05, 5 / 6, 1.0
D = E * t^3 / (12 * (1 - ν^2))
G = E / (2 * (1 + ν))
w_exact = 1 / (4 * π^4 * D) + 1 / (2 * π^2 * κ * G * t)
function center_deflection(n)
p = square_tri(n)
N = size(p.vertices, 2)
fixed = Int[]
for i in 1:N
x, y = p.vertices[1, i], p.vertices[2, i]
onx = x < 1e-12 || x > 1 - 1e-12
ony = y < 1e-12 || y > 1 - 1e-12
(onx || ony) || continue
push!(fixed, 3i - 2) # w = 0 on the boundary
ony && push!(fixed, 3i - 1) # θₓ = 0 on the y-edges
onx && push!(fixed, 3i) # θ_y = 0 on the x-edges
end
loads = zeros(3N)
for i in 1:N
loads[3i - 2] = q0 * sin(π * p.vertices[1, i]) * sin(π * p.vertices[2, i]) / N
end
w = solve_mindlin_plate(p, E, ν, t, fixed, loads)
center = argmin([norm(p.vertices[:, i] .- [0.5, 0.5]) for i in 1:N])
w[3 * center - 2]
end
for n in (8, 16, 32)
wc = center_deflection(n)
println("n = ", n, " centre w = ", round(wc; digits = 8),
" (", round(abs(wc - w_exact) / w_exact * 100; digits = 1), "% error)")
end
println("exact = ", round(w_exact; digits = 8))n = 8 centre w = 6.21e-6 (72.7% error)
n = 16 centre w = 1.405e-5 (38.2% error)
n = 32 centre w = 1.933e-5 (15.0% error)
exact = 2.274e-5
The deflection converges to the exact value as the mesh refines. Linear Mindlin triangles are noticeably stiff (transverse shear locks them, so they underestimate the deflection), which is why the convergence is gradual — it is the price of a locking-free but low-order element. The shear term 1/(2π²κ G t) vanishes as t → 0, recovering the thin-plate (Kirchhoff) result.
Flat shells (membrane + bending)
flat_shell_stiffness couples the Mindlin bending block with an in-plane membrane block, so a shell carries stretch and bending together. The stiffness is symmetric, and in the limit of no coupling the blocks decouple:
Kshell = flat_shell_stiffness(plate, E, ν, t)
Kplate = mindlin_plate_stiffness(plate, E, ν, t)
println("flat-shell stiffness symmetric: ", Kshell ≈ Kshell')
println("size: ", size(Kshell), " (6 dofs/node: u, θ)")
println("Mindlin block size: ", size(Kplate), " (3 dofs/node: w, θ)")flat-shell stiffness symmetric: true
size: (1280, 1280) (6 dofs/node: u, θ)
Mindlin block size: (768, 768) (3 dofs/node: w, θ)
The physics API
Both models plug into the familiar solve(Physics(), mesh, material, t; …) form, so they accept the same region => value boundary conditions as the solid physics:
mhp = square_tri(8)
Nhp = size(mhp.vertices, 2)
edge = Int[]
for i in 1:Nhp
x, y = mhp.vertices[1, i], mhp.vertices[2, i]
(x < 1e-12 || x > 1 - 1e-12 || y < 1e-12 || y > 1 - 1e-12) && push!(edge, 3i - 2)
end
w_physics = solve(MindlinPlate(), mhp, steel, 0.01; fixed = edge, pressure = 1e3)
println("max |w| (MindlinPlate) = ", round(maximum(abs, w_physics); digits = 6))max |w| (MindlinPlate) = 3.0e-5
Next steps
- Plates — the thin-plate (Kirchhoff–Love) limit and the Navier-series check.
- Beams — the 1D bending elements these 2D elements generalize.
- Linear elasticity — the 3D solid behind membrane and bending.
