Cantilever Bending Roll-up (corotational)

A Cantilever beam is subjected to a total end-moment about the Y axis \(M_y=n 2 \pi E I / L\), where \(n\) is the number of rotations ( 2 in this example).

See ASDShellQ4 Element Example 1

[1]:
import matplotlib.pyplot as plt
import numpy as np
from openseespy import opensees as ops

import opstool as opst

Set up the model

[2]:
# model and section
ops.wipe()
ops.model("basic", "-ndm", 3, "-ndf", 6)
E = 1e4
h = 1.0
ops.section("ElasticMembranePlateSection", 1, E, 0.0, h)

# mesh
Lx = 20.0
Ly = 1.0
Nx = 20
Ny = 1
dLx = Lx / Nx
dLy = Ly / Ny
for j in range(Ny + 1):
    offset = j * (Nx + 1)
    jY = j * dLy
    for i in range(Nx + 1):
        iX = i * dLx
        ops.node(offset + i + 1, iX, jY, 0.0)
ele_id = 1
for j in range(Ny):
    for i in range(Nx):
        qids = (j * (Nx + 1) + i + 1, j * (Nx + 1) + i + 2, (j + 1) * (Nx + 1) + i + 2, (j + 1) * (Nx + 1) + i + 1)
        ops.element("ASDShellQ4", ele_id, *qids, 1, "-corotational")
        ele_id += 1

# fix
for j in range(Ny + 1):
    ops.fix(j * (Nx + 1) + 1, 1, 1, 1, 1, 1, 1)

# load
Nrolls = 2
M = Nrolls * 2.0 * np.pi * E * h**3 / 12 / Lx
dM = M / Ny / 2
ops.timeSeries("Linear", 1)
ops.pattern("Plain", 1, 1)
for j in range(Ny):
    i = Nx - 1
    n1 = j * (Nx + 1) + i + 2
    n2 = (j + 1) * (Nx + 1) + i + 2
    ops.load(n1, 0, 0, 0, 0, -dM, 0)
    ops.load(n2, 0, 0, 0, 0, -dM, 0)
Using ASDShellQ4 - Developed by: Massimo Petracca, Guido Camata, ASDEA Software Technology
[3]:
fig = opst.vis.plotly.plot_model()
fig.show()
fig.write_html("model.html", full_html=False, include_plotlyjs="cdn")

Data type cannot be displayed: application/vnd.plotly.v1+json

Analysis

[4]:
# analysis
duration = 1.0
nsteps = 40
dt = duration / nsteps
dt_record = 0.2
ops.constraints("Transformation")
ops.numberer("RCM")
ops.system("UmfPack")
ops.test("NormDispIncr", 1.0e-5, 100, 0)
ops.algorithm("Newton")
ops.integrator("LoadControl", dt)
ops.analysis("Static")
[5]:
ODB = opst.post.CreateODB(odb_tag="CantileverBendingRollup", project_gauss_to_nodes="copy")
for _ in range(nsteps):
    ops.analyze(1)
    ODB.fetch_response_step()
ODB.save_response()
OPSTOOL ::  All responses data with _odb_tag = CantileverBendingRollup saved in
.opstool.output/RespStepData-CantileverBendingRollup.nc!

Post-processing

Nodal response

scale=False is used to avoid scaling the deformed shape in the plot. This is necessary for this example because scaling would make the deformation appear incorrect.

[6]:
opst.vis.plotly.set_plot_props(point_size=0)

fig = opst.vis.plotly.plot_nodal_responses_animation(
    odb_tag="CantileverBendingRollup",
    framerate=8,  # frames per second, 40 steps, 5 seconds total
    resp_type="disp",
    resp_dof=["UX", "UY", "UZ"],
    defo_scale=1.0,
    unit_symbol="mm",
)
fig.show()
fig.write_html("nodal_resp.html", full_html=False, include_plotlyjs="cdn")
OPSTOOL ::  Loading response data from .opstool.output/RespStepData-CantileverBendingRollup.nc ...

Data type cannot be displayed: application/vnd.plotly.v1+json

Shell Nodal Stresses

[7]:
fig = opst.vis.plotly.plot_unstruct_responses(
    odb_tag="CantileverBendingRollup",
    slides=True,
    ele_type="Shell",
    resp_type="StressesAtNodes",  # nodal stress response, "AtNodes"
    resp_dof="sigma22",  # sigma11, sigma22, sigma12, sigma13, sigma23
    shell_fiber_loc="bottom",  # shell_fiber_loc can be "top", "bottom", or "mid" for shell elements, also int
    # unit_symbol="kPa",
    # unit_factor=1,  # unit_factor is used to convert the response value, if MPa, set it to 1e-3
    show_defo=True,
    defo_scale=1.0,  # deformation scale factor not applied, set to False or 1.0
)
fig.show()
fig.write_html("shell_resp.html", full_html=False, include_plotlyjs="cdn")
OPSTOOL ::  Loading response data from .opstool.output/RespStepData-CantileverBendingRollup.nc ...

Data type cannot be displayed: application/vnd.plotly.v1+json

Xarray data processing

[8]:
CNode = (Nx + 1) * (Ny + 1)

node_resp = opst.post.get_nodal_responses(odb_tag="CantileverBendingRollup")

print(node_resp)
OPSTOOL ::  Loading all response data from .opstool.output/RespStepData-CantileverBendingRollup.nc ...
<xarray.Dataset> Size: 255kB
Dimensions:             (time: 41, nodeTags: 42, DOFs: 6)
Coordinates:
  * time                (time) float32 164B 0.0 0.025 0.05 ... 0.95 0.975 1.0
  * nodeTags            (nodeTags) int32 168B 1 2 3 4 5 6 ... 37 38 39 40 41 42
  * DOFs                (DOFs) <U2 48B 'UX' 'UY' 'UZ' 'RX' 'RY' 'RZ'
Data variables:
    disp                (time, nodeTags, DOFs) float32 41kB 0.0 ... 3.595e-10
    vel                 (time, nodeTags, DOFs) float32 41kB 0.0 0.0 ... 0.0 0.0
    accel               (time, nodeTags, DOFs) float32 41kB 0.0 0.0 ... 0.0 0.0
    reaction            (time, nodeTags, DOFs) float32 41kB 7.801e-14 ... 2.2...
    reactionIncInertia  (time, nodeTags, DOFs) float32 41kB 7.801e-14 ... 2.2...
    rayleighForces      (time, nodeTags, DOFs) float32 41kB 0.0 0.0 ... 0.0 0.0
    pressure            (time, nodeTags) float32 7kB 0.0 0.0 0.0 ... 0.0 0.0 0.0
Attributes:
    UX:       Displacement in X direction
    UY:       Displacement in Y direction
    UZ:       Displacement in Z direction
    RX:       Rotation about X axis
    RY:       Rotation about Y axis
    RZ:       Rotation about Z axis
[9]:
disp = node_resp["disp"].sel(nodeTags=CNode)
uz = disp.sel(DOFs="UZ")
ux = disp.sel(DOFs="UX")
uy = disp.sel(DOFs="UY")
ry = -disp.sel(DOFs="RY")
[10]:
plt.plot(uz.time, uz.values, "-bo", label="UZ")
plt.plot(ry.time, ry.values, "--r^", label="RY")
plt.plot(ux.time, ux.values, "-g*", label="UX")
plt.xlabel("Time (s)")
plt.ylabel("Displacement")
plt.legend()
plt.show()
../../../_images/examples_post_cantilever-roll-up_src_21_0.png