BeamBending#

A rectangular section bent past yield.

The plastic front moves in from the outer fibres, leaving an elastic core of half-depth \(c = \varepsilon_y/\kappa\). Integrating the stress over the section gives

\[\frac{M}{M_e} = \frac32 - \frac12\left(\frac{\kappa_e}{\kappa}\right)^2\]

with \(M_e = \sigma_y w h^2/6\) at first yield and \(M_p = \sigma_y w h^2/4\) once the core has vanished. Their ratio is the shape factor, exactly 3/2 for a rectangle — independent of material, size and mesh.

The ends are given a linear axial displacement, which imposes the plane-sections kinematics the closed form assumes, so this tests the constitutive response rather than beam theory. The sweep stops at \(\kappa/\kappa_e = 4\): with no hardening the curve approaches 3/2 without reaching it.

Reference#

Chakrabarty, Theory of Plasticity, 3rd ed., Elsevier (2006), ch. 3.

BeamBending
BeamBending
  • Moment-curvature of a rectangular section
  • Stress through the section: the elastic core shrinks
M_e = 83333 N.mm, M_p = 125000 N.mm, shape factor = 1.500


======= elastic problem at iteration 0 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 9.914813358561e-15


======= elastic problem at iteration 1 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 1.354503489995e-14


======= elastic problem at iteration 2 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 4.952211528844e-03
At Newton iteration 3 relative norm is 2.371505112818e-05
At Newton iteration 4 relative norm is 5.752090419208e-10
At Newton iteration 5 relative norm is 1.166346001912e-14


======= elastic problem at iteration 3 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 7.846123816232e-03
At Newton iteration 3 relative norm is 3.977265766034e-05
At Newton iteration 4 relative norm is 1.917222017193e-08
At Newton iteration 5 relative norm is 2.337201284208e-14


======= elastic problem at iteration 4 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 1.228954348053e-02
At Newton iteration 3 relative norm is 1.593044545820e-03
At Newton iteration 4 relative norm is 1.254434127300e-05
At Newton iteration 5 relative norm is 1.628854576204e-09
At Newton iteration 6 relative norm is 3.675075308906e-14


======= elastic problem at iteration 5 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 8.241480261814e-03
At Newton iteration 3 relative norm is 2.351620835505e-05
At Newton iteration 4 relative norm is 2.017522115952e-10
At Newton iteration 5 relative norm is 4.693948764580e-14


======= elastic problem at iteration 6 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 2.215693215890e-03
At Newton iteration 3 relative norm is 1.958380994561e-06
At Newton iteration 4 relative norm is 2.146014267670e-12


======= elastic problem at iteration 7 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 3.349160557800e-04
At Newton iteration 3 relative norm is 5.845943724850e-09
At Newton iteration 4 relative norm is 8.326913701400e-14


======= elastic problem at iteration 8 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 1.117056869328e-03
At Newton iteration 3 relative norm is 1.642645443014e-04
At Newton iteration 4 relative norm is 2.133616243945e-06
At Newton iteration 5 relative norm is 3.092144534243e-10
At Newton iteration 6 relative norm is 1.037882058749e-13


======= elastic problem at iteration 9 =======
At Newton iteration 1 relative norm is 1.000000000000e+00
At Newton iteration 2 relative norm is 8.709189750462e-03
At Newton iteration 3 relative norm is 1.902986569058e-04
At Newton iteration 4 relative norm is 8.905060705193e-08
At Newton iteration 5 relative norm is 1.630443872220e-13
worst error over the sweep: 1.62 %
M/M_e reaches 1.4531, approaching the shape factor 1.5

Generate movie 01/10 (10.00 %) 1.10 s
Generate movie 02/10 (20.00 %) 868.56 ms
Generate movie 03/10 (30.00 %) 753.18 ms
Generate movie 04/10 (40.00 %) 640.22 ms
Generate movie 05/10 (50.00 %) 535.33 ms
Generate movie 06/10 (60.00 %) 435.31 ms
Generate movie 07/10 (70.00 %) 326.01 ms
Generate movie 08/10 (80.00 %) 220.83 ms
Generate movie 09/10 (90.00 %) 110.59 ms
Generate movie 10/10 (100.00 %) 0.00 µs

 33 import numpy as np
 34 from scipy.integrate import simpson
 35
 36 from EasyFEA import Folder, Matplotlib, ElemType, Models, PyVista, Simulations
 37 from EasyFEA.Geoms import Domain, Line
 38 from EasyFEA.Models.Elastic._laws import Isotropic
 39
 40 # ----------------------------------------------
 41 # Configuration
 42 # ----------------------------------------------
 43 folder = Folder.Results_Dir()
 44
 45 L, h, w = 80.0, 20.0, 5.0  # mm — length, depth, thickness
 46 E, v = 210000.0, 0.3  # MPa
 47 sigma_y = 250.0  # MPa
 48
 49 M_e = sigma_y * w * h**2 / 6  # first yield
 50 M_p = sigma_y * w * h**2 / 4  # fully plastic
 51 kappa_e = 2 * sigma_y / (E * h)  # curvature at first yield
 52
 53 print(f"M_e = {M_e:.0f} N.mm, M_p = {M_p:.0f} N.mm, shape factor = {M_p / M_e:.3f}")
 54
 55
 56 def Exact(ratio):
 57     """M/M_e as a function of kappa/kappa_e; linear until the outer fibre yields."""
 58     return np.where(ratio <= 1.0, ratio, 1.5 - 0.5 / np.maximum(ratio, 1e-12) ** 2)
 59
 60
 61 # ----------------------------------------------
 62 # Mesh
 63 # ----------------------------------------------
 64 domain = Domain((0, -h / 2), (L, h / 2), h / 8)
 65 mesh = domain.Mesh_2D(
 66     [],
 67     ElemType.QUAD9,
 68     additionalLines=[Line((0, 0), (L, 0))],
 69     isOrganised=True,
 70 )
 71 # mesh = domain.Mesh_2D([], ElemType.QUAD8, isOrganised=True)
 72
 73 nodesX0 = mesh.Nodes_Conditions(lambda x, y, z: x == 0)
 74 nodesXL = mesh.Nodes_Conditions(lambda x, y, z: x == L)
 75 nodesMid = mesh.Nodes_Conditions(lambda x, y, z: np.isclose(x, L / 2))
 76 origin = mesh.Nodes_Conditions(lambda x, y, z: (x == 0) & (np.abs(y) < 1e-9))
 77
 78 yMid = mesh.coord[nodesMid, 1]
 79 order = np.argsort(yMid)
 80 yMid = yMid[order]
 81
 82 # ----------------------------------------------
 83 # Simulation
 84 # ----------------------------------------------
 85 material = Models.InElastic.Behavior(
 86     2,
 87     Isotropic(3, E=E, v=v),
 88     yieldSurface=Models.InElastic.Yield.VonMises(sigma_y),  # perfectly plastic
 89     thickness=w,
 90     planeStress=True,
 91 )
 92 simu = Simulations.InElastic(mesh, material)
 93
 94 # Bend it, curvature by curvature
 95 ratios = np.arange(0.4, 4.01, 0.4)
 96 moments, profiles = [], {}
 97
 98 for ratio in ratios:
 99     kappa = ratio * kappa_e
100     simu.Bc_Init()
101     simu.add_dirichlet(nodesX0, [0], ["x"])
102     simu.add_dirichlet(origin, [0], ["y"])
103     # plane sections stay plane: u_x = -kappa * L * y at the far end
104     simu.add_dirichlet(nodesXL, [lambda x, y, z: -kappa * L * y], ["x"])
105     simu.Solve()
106     simu.Save_Iter()
107
108     sig_xx = simu.Result("Sxx")[nodesMid][order]
109     # Simpson, since sig_xx * y is quadratic in y while the section is elastic
110     moments.append(abs(simpson(sig_xx * yMid, x=yMid) * w))
111     profiles[ratio] = sig_xx
112
113 moments = np.array(moments)
114 exact = Exact(ratios)
115
116 errors = 100 * np.abs(moments / M_e - exact) / exact
117
118 shapeFactor = moments[-1] / M_e
119 print(f"worst error over the sweep: {errors.max():.2f} %")
120 print(f"M/M_e reaches {shapeFactor:.4f}, approaching the shape factor 1.5")
121
122 # only the shape factor is asserted: it is a pure number, independent of material, size and
123 # mesh, where the error against the closed form moves with any mesh change
124 assert 1.4 < shapeFactor < 1.5, "the shape factor is not approached"
125
126 # ----------------------------------------------
127 # Results
128 # ----------------------------------------------
129 PyVista.Plot_BoundaryConditions(simu).show()
130
131 # the two curves lie on top of each other, so the error gets a panel of its own
132 fig, (ax, axErr) = Matplotlib.plt.subplots(
133     2, 1, sharex=True, figsize=(6.4, 6.0), gridspec_kw={"height_ratios": [3, 1]}
134 )
135
136 fine = np.linspace(0.05, ratios[-1], 400)
137 ax.axvspan(0, 1, color="0.93", zorder=0)
138 ax.text(0.5, 0.07, "elastic", ha="center", fontsize=8, color="0.4")
139 ax.plot(fine, Exact(fine), "k-", lw=1.2, label="Chakrabarty")
140 ax.plot(ratios, moments / M_e, "o", ms=6, mfc="none", mew=1.3, label="EasyFEA")
141 ax.axhline(1.5, ls="--", c="r", lw=0.9)
142 ax.text(
143     ratios[-1], 1.505, "shape factor $M_p/M_e = 3/2$  ", c="r", fontsize=8, ha="right"
144 )
145 ax.set_ylabel("$M/M_e$")
146 ax.set_ylim(0, 1.62)
147 ax.set_xlim(0, ratios[-1] + 0.1)
148 ax.set_title("Moment-curvature of a rectangular section")
149 ax.legend(fontsize=8, loc="lower right")
150 ax.grid(alpha=0.3)
151
152 axErr.axvspan(0, 1, color="0.93", zorder=0)
153 axErr.plot(ratios, errors, "o-", ms=4, lw=1)
154 axErr.set_xlabel(r"$\kappa/\kappa_e$")
155 axErr.set_ylabel("error [%]")
156 axErr.set_ylim(0, max(1.05 * errors.max(), 0.5))
157 axErr.grid(alpha=0.3)
158 fig.align_ylabels()
159
160 # the plastic front eating into the section
161 ax = Matplotlib.Init_Axes()
162 yFine = np.linspace(-h / 2, h / 2, 400)
163 for i, ratio in enumerate((0.8, 1.6, 2.4, 4.0)):
164     idx = int(np.argmin(np.abs(ratios - ratio)))
165     ax.plot(
166         profiles[ratios[idx]], yMid, label=rf"$\kappa/\kappa_e$ = {ratios[idx]:.1f}"
167     )
168     # exact: linear inside the elastic core of half-depth c, saturated at sigma_y outside.
169     # the imposed u_x = -kappa L y puts the top fibre in compression, hence the sign
170     core = h / (2 * ratios[idx])
171     ax.plot(
172         -sigma_y * np.clip(yFine / core, -1, 1),
173         yFine,
174         "k--",
175         lw=0.8,
176         label="exact" if i == 0 else None,
177     )
178 ax.axvline(sigma_y, ls=":", c="k", lw=0.8)
179 ax.axvline(-sigma_y, ls=":", c="k", lw=0.8)
180 ax.set_xlabel(r"$\sigma_{xx}$ [MPa]")
181 ax.set_ylabel("$y$ [mm]")
182 ax.set_title("Stress through the section: the elastic core shrinks")
183 ax.legend()
184 ax.grid(alpha=0.3)
185
186 PyVista.Movie_simu(simu, "p", folder, "p.gif", deformFactor=2)
187
188 Matplotlib.plt.show()

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

Gallery generated by Sphinx-Gallery