Cantilever plate¶
A plate of dimensions 100mm x 50mm x 0.5mm clamped at one end. It is subjected to concentrated forces of 5N at each corner at the tip.
A reference solution is computed with ABAQUS for the following shell elements:
| Type | u_max | S_max |
|---|---|---|
| S3 | 30.36 | 423.6 |
| S4 | 30.54 | 438.5 |
| S4R | 30.63 | 440.2 |
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)
# Material parameters
material = IsotropicElasticityPlaneStress(E=200000.0, nu=0.3)
Triangular shell elements¶
In [2]:
# Define nodes and elements of the plate
nodes, elements = rect_tri(10, 5, Lx=100.0, Ly=50.0, variant="zigzag")
nodes = torch.hstack([nodes, torch.zeros((nodes.size(0), 1))])
# Define Shell model
tri = Shell(nodes, elements, material, thickness=0.5)
# Define masks for boundaries
left = nodes[:, 0] < 0.01
right = nodes[:, 0] > 99.9
front = nodes[:, 1] < 0.01
back = nodes[:, 1] > 49.99
# Apply load and displacement boundary conditions
tri.forces[right & front, 2] = -5
tri.forces[right & back, 2] = -5
tri.constraints[left] = True
# Solve
u_tri, f, σ_tri, _, _ = tri.solve(aggregate_integration_points=False)
# Displacement on deformed configuration
tri.plot(
u_tri[:, 0:3],
node_property={"u": torch.linalg.norm(u_tri[:, 0:3], dim=1)},
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"
)
Quadrilateral shell elements¶
In [4]:
# Define nodes and elements of the plate
nodes, elements = rect_quad(10, 5, Lx=100.0, Ly=50.0)
nodes = torch.hstack([nodes, torch.zeros((nodes.size(0), 1))])
# Define Shell model
quad = Shell(nodes, elements, material, thickness=0.5)
# Define masks for boundaries
left = nodes[:, 0] < 0.01
right = nodes[:, 0] > 99.9
front = nodes[:, 1] < 0.01
back = nodes[:, 1] > 49.99
# Apply load and displacement boundary conditions
quad.forces[right & front, 2] = -5
quad.forces[right & back, 2] = -5
quad.constraints[left] = True
# Solve
u_quad, f, σ_quad, _, _ = quad.solve(aggregate_integration_points=False)
# Displacement on deformed configuration
quad.plot(
u_quad[:, 0:3],
node_property={"u": torch.linalg.norm(u_quad[:, 0:3], dim=1)},
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",
)
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} "
f"{torch.min(u_tri[:, 0:3]):8.2f} {torch.max(mises_tri):8.1f}"
)
print(
f"{'Quad1':<7} {quad.n_elem:>9} "
f"{torch.min(u_quad[:, 0:3]):8.2f} {torch.max(mises_quad):8.1f}"
)
Type Elements u_max S_max Tria1 72 -30.72 430.6 Quad1 36 -30.53 437.9