Center-loaded plate¶

Open In Colab Binder

A square plate of 100x100 is fully clamped at all edges and subjected to a concentrated force F=16.367 at the center. A symmetric quarter model is computed.

A reference solution is computed with ABAQUS for the following shell elements:

Type u_max S_max
S3 -3.773 72.60
S4 -3.987 89.90
S4R -4.015 86.96

All reference values use the same mesh, and the plate is solved with both shell element types of torch-fem on those same nodes, so the triangles compare to S3 and the quadrilaterals to S4 and S4R.

In [1]:
import torch

from torchfem import Shell
from torchfem.materials import IsotropicElasticityPlaneStress
from torchfem.mesh import rect_quad, rect_tri

# Set default data type to double precision
torch.set_default_dtype(torch.float64)

# Constants
L = 100.0
F = -16.367

# Material parameters
mat = IsotropicElasticityPlaneStress(E=10000.0, nu=0.3)

Triangular shell elements¶

The symmetric quarter model is mirrored in x-direction and y-direction.

In [2]:
# Define nodes and elements of the plate
nodes, elements = rect_tri(9, 9, 0.5 * L, 0.5 * L, variant="zigzag")
nodes = torch.hstack([nodes, torch.zeros((len(nodes), 1))])

# Create Shell model
tri = Shell(nodes, elements, mat)

# Boundaries
top = nodes[:, 1] > (L / 2.0 - 0.01)
bottom = nodes[:, 1] < 0.01
left = nodes[:, 0] < 0.01
right = nodes[:, 0] > (L / 2.0 - 0.01)

# Force at the center, clamped outer edges and symmetry on the cut edges
tri.forces[0, 2] = F
tri.constraints[top] = True
tri.constraints[right] = True
tri.constraints[left, 0] = True
tri.constraints[left, 4] = True
tri.constraints[left, 5] = True
tri.constraints[bottom, 1] = True
tri.constraints[bottom, 3] = True
tri.constraints[bottom, 5] = True

# Solve
u_tri, f, σ_tri, _, _ = tri.solve(aggregate_integration_points=False)

# Displacement on deformed configuration, scaled by a factor of 10
tri.plot(
    10.0 * u_tri[:, 0:3],
    node_property={"u": torch.linalg.norm(u_tri[:, 0:3], dim=1)},
    mirror=(True, True, False),
    bcs=True,
)

v. Mises stress¶

In [3]:
# v. Mises stress at the top of the shell. Integration points run over the in-plane
# points and the thickness stations, of which the last one sits at +t/2.
s = σ_tri.reshape(-1, tri.n_z, tri.n_elem, 2, 2)[:, -1]
mises_tri = (
    torch.sqrt(
        s[..., 0, 0] ** 2
        - s[..., 0, 0] * s[..., 1, 1]
        + s[..., 1, 1] ** 2
        + 3 * s[..., 0, 1] ** 2
    )
    .max(dim=0)
    .values
)

tri.plot(
    u_tri[:, 0:3],
    element_property={"v. Mises stress (top)": mises_tri},
    cmap="inferno",
    mirror=(True, True, False),
)

Quadrilateral shell elements¶

The symmetric quarter model is mirrored in x-direction and y-direction.

In [4]:
# Define nodes and elements of the plate
nodes, elements = rect_quad(9, 9, 0.5 * L, 0.5 * L)
nodes = torch.hstack([nodes, torch.zeros((len(nodes), 1))])

# Create Shell model
quad = Shell(nodes, elements, mat)

# Boundaries
top = nodes[:, 1] > (L / 2.0 - 0.01)
bottom = nodes[:, 1] < 0.01
left = nodes[:, 0] < 0.01
right = nodes[:, 0] > (L / 2.0 - 0.01)

# Force at the center, clamped outer edges and symmetry on the cut edges
quad.forces[0, 2] = F
quad.constraints[top] = True
quad.constraints[right] = True
quad.constraints[left, 0] = True
quad.constraints[left, 4] = True
quad.constraints[left, 5] = True
quad.constraints[bottom, 1] = True
quad.constraints[bottom, 3] = True
quad.constraints[bottom, 5] = True

# Solve
u_quad, f, σ_quad, _, _ = quad.solve(aggregate_integration_points=False)

# Displacement on deformed configuration, scaled by a factor of 10
quad.plot(
    10.0 * u_quad[:, 0:3],
    node_property={"u": torch.linalg.norm(u_quad[:, 0:3], dim=1)},
    mirror=(True, True, False),
    bcs=True,
)

v. Mises stress¶

In [5]:
# v. Mises stress at the top of the shell. Integration points run over the in-plane
# points and the thickness stations, of which the last one sits at +t/2.
s = σ_quad.reshape(-1, quad.n_z, quad.n_elem, 2, 2)[:, -1]
mises_quad = (
    torch.sqrt(
        s[..., 0, 0] ** 2
        - s[..., 0, 0] * s[..., 1, 1]
        + s[..., 1, 1] ** 2
        + 3 * s[..., 0, 1] ** 2
    )
    .max(dim=0)
    .values
)

quad.plot(
    u_quad[:, 0:3],
    element_property={"v. Mises stress (top)": mises_quad},
    cmap="inferno",
    mirror=(True, True, False),
)

Comparison¶

Both meshes carry the same nodes, so the quadrilaterals use half as many elements.

In [6]:
print(f"{'Type':<7} {'Elements':>9} {'u_max':>8} {'S_max':>8}")
print(f"{'Tria1':<7} {tri.n_elem:>9} {u_tri.min():8.3f} {torch.max(mises_tri):8.2f}")
print(f"{'Quad1':<7} {quad.n_elem:>9} {u_quad.min():8.3f} {torch.max(mises_quad):8.2f}")
Type     Elements    u_max    S_max
Tria1         128   -3.999    78.74
Quad1          64   -3.986    89.76