Note
Go to the end to download the full example code.
Animated torsional-shear loading#
This example demonstrates how to create a Boundary
for torsional
loading. This is somewhat more complicated than a simple boundary condition with
identical mesh-point values because the values of the mesh-points are different.
However, this is not a problem. FElupe supports arrays to be passed as the value
-
argument of a Boundary
. This is even possible in a
Step
with the ramp
-argument.
import matplotlib.pyplot as plt
import numpy as np
import felupe as fem
mesh = fem.mesh.Triangle(n=3).expand(n=6)
field = fem.FieldContainer([fem.Field(fem.RegionHexahedron(mesh), dim=3)])
boundaries = {
"bottom": fem.Boundary(field[0], fz=0),
"top": fem.Boundary(field[0], fz=1),
}
solid = fem.SolidBody(umat=fem.NeoHookeCompressible(mu=1, lmbda=2), field=field)
angles_deg = fem.math.linsteps([0, -30, 0], num=10)
move = []
for phi in angles_deg:
top = mesh.points[boundaries["top"].points]
top_rotated = fem.mesh.rotate(
points=top,
cells=None,
cell_type=None,
angle_deg=phi,
axis=2,
center=[0, 0, 1],
)[0]
move.append(top_rotated - top)
The reaction moment on the centerpoint of the right end face is tracked by a
callback()
function when we evaluate()
the Job
.
During the callback, the animated deformed body is recorded in a GIF-file. After all
frames are recorded, it is important to close()
the plotter.
moment = []
plotter = field.plot(
"Principal Values of Logarithmic Strain", clim=[0, 0.2], off_screen=True
)
plotter.open_gif("result.gif", fps=5)
def record(stepnumber, substepnumber, substep, plotter):
"Update the mesh-points and the scalars of the plotter."
if substepnumber in np.arange(len(move), step=2):
name = plotter.mesh.active_scalars_info.name
data = substep.x.evaluate.log_strain(tensor=False).mean(-2)[-1]
plotter.mesh.points[:] = mesh.points + field[0].values
plotter.mesh[name] = data
plotter.write_frame()
# evaluate the reaction moment at the centerpoint of the right end face
forces = substep.fun
M = fem.tools.moment(field, forces, boundaries["top"], centerpoint=[0, 0, 1])
moment.append(M)
step = fem.Step(items=[solid], ramp={boundaries["top"]: move}, boundaries=boundaries)
job = fem.Job(steps=[step], callback=record, plotter=plotter).evaluate()
plotter.close()

Finally, let’s plot the reaction moment vs. torsion angle curve.
fig, ax = plt.subplots()
ax.plot(abs(angles_deg), abs(np.array(moment)[:, 2]), "o-")
ax.set_xlabel(r"Torsion Angle $|\phi_3|$ in deg $\rightarrow$")
ax.set_ylabel(r"Torsion Moment $|M_3|$ in Nmm $\rightarrow$")

Total running time of the script: (0 minutes 2.336 seconds)