RasmahRasmah

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.