Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/mechanical-engineering/stress_analysis.tex
51 views
unlisted
1
\documentclass[11pt,a4paper]{article}
2
3
% Document Setup
4
\usepackage[utf8]{inputenc}
5
\usepackage[T1]{fontenc}
6
\usepackage{lmodern}
7
\usepackage[margin=1in]{geometry}
8
\usepackage{amsmath,amssymb}
9
\usepackage{siunitx}
10
\usepackage{booktabs}
11
\usepackage{float}
12
\usepackage{caption}
13
\usepackage{hyperref}
14
15
% PythonTeX Setup
16
\usepackage[makestderr]{pythontex}
17
18
\title{Stress Analysis: Mohr's Circle and Failure Theories}
19
\author{Mechanical Engineering Laboratory}
20
\date{\today}
21
22
\begin{document}
23
\maketitle
24
25
\begin{abstract}
26
This report presents computational analysis of stress states in solid mechanics. We examine stress transformation using Mohr's circle, principal stresses, von Mises equivalent stress, and common failure theories. Python-based computations provide quantitative analysis with dynamic visualization.
27
\end{abstract}
28
29
\tableofcontents
30
\newpage
31
32
\section{Introduction to Stress Analysis}
33
34
Stress analysis is fundamental to mechanical design and failure prediction. This analysis covers:
35
\begin{itemize}
36
\item Plane stress transformation
37
\item Mohr's circle construction
38
\item Principal stress calculation
39
\item von Mises yield criterion
40
\item Failure theories (Tresca, Rankine, Mohr-Coulomb)
41
\end{itemize}
42
43
% Initialize Python environment
44
\begin{pycode}
45
import numpy as np
46
import matplotlib.pyplot as plt
47
from matplotlib.patches import Circle, FancyArrowPatch
48
49
plt.rcParams['figure.figsize'] = (8, 5)
50
plt.rcParams['font.size'] = 10
51
plt.rcParams['text.usetex'] = True
52
53
def save_fig(filename):
54
plt.savefig(filename, dpi=150, bbox_inches='tight')
55
plt.close()
56
\end{pycode}
57
58
\section{Plane Stress State}
59
60
For a 2D stress state, the stress tensor is:
61
\begin{equation}
62
\boldsymbol{\sigma} = \begin{pmatrix} \sigma_x & \tau_{xy} \\ \tau_{xy} & \sigma_y \end{pmatrix}
63
\end{equation}
64
65
\subsection{Stress Transformation}
66
67
Stresses on a rotated plane (angle $\theta$ from x-axis):
68
\begin{align}
69
\sigma_{x'} &= \frac{\sigma_x + \sigma_y}{2} + \frac{\sigma_x - \sigma_y}{2}\cos(2\theta) + \tau_{xy}\sin(2\theta) \\
70
\tau_{x'y'} &= -\frac{\sigma_x - \sigma_y}{2}\sin(2\theta) + \tau_{xy}\cos(2\theta)
71
\end{align}
72
73
\begin{pycode}
74
# Define stress state
75
sigma_x = 80 # MPa
76
sigma_y = -40 # MPa
77
tau_xy = 30 # MPa
78
79
# Calculate center and radius of Mohr's circle
80
sigma_avg = (sigma_x + sigma_y) / 2
81
R = np.sqrt(((sigma_x - sigma_y) / 2)**2 + tau_xy**2)
82
83
# Principal stresses
84
sigma_1 = sigma_avg + R
85
sigma_2 = sigma_avg - R
86
87
# Principal angle
88
theta_p = 0.5 * np.arctan2(2*tau_xy, sigma_x - sigma_y)
89
theta_p_deg = np.degrees(theta_p)
90
91
# Maximum shear stress
92
tau_max = R
93
theta_s = theta_p + np.pi/4
94
95
# Stress transformation for various angles
96
theta = np.linspace(0, np.pi, 180)
97
sigma_n = sigma_avg + (sigma_x - sigma_y)/2 * np.cos(2*theta) + tau_xy * np.sin(2*theta)
98
tau_nt = -(sigma_x - sigma_y)/2 * np.sin(2*theta) + tau_xy * np.cos(2*theta)
99
100
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
101
102
# Mohr's Circle
103
circle = Circle((sigma_avg, 0), R, fill=False, color='blue', linewidth=2)
104
ax1.add_patch(circle)
105
106
# Plot key points
107
ax1.plot(sigma_x, tau_xy, 'ro', markersize=10, label=f'X: ({sigma_x}, {tau_xy})')
108
ax1.plot(sigma_y, -tau_xy, 'go', markersize=10, label=f'Y: ({sigma_y}, {-tau_xy})')
109
ax1.plot(sigma_1, 0, 'bs', markersize=10, label=f'$\\sigma_1$: {sigma_1:.1f}')
110
ax1.plot(sigma_2, 0, 'bs', markersize=10, label=f'$\\sigma_2$: {sigma_2:.1f}')
111
ax1.plot(sigma_avg, tau_max, 'r^', markersize=10)
112
ax1.plot(sigma_avg, -tau_max, 'r^', markersize=10)
113
114
# Draw XY line
115
ax1.plot([sigma_x, sigma_y], [tau_xy, -tau_xy], 'k--', linewidth=1)
116
117
ax1.axhline(0, color='k', linewidth=0.5)
118
ax1.axvline(0, color='k', linewidth=0.5)
119
ax1.set_xlabel('Normal Stress $\\sigma$ (MPa)')
120
ax1.set_ylabel('Shear Stress $\\tau$ (MPa)')
121
ax1.set_title("Mohr's Circle for Plane Stress")
122
ax1.legend(loc='upper right', fontsize=8)
123
ax1.grid(True, alpha=0.3)
124
ax1.axis('equal')
125
ax1.set_xlim(-80, 120)
126
ax1.set_ylim(-80, 80)
127
128
# Stress variation with angle
129
ax2.plot(np.degrees(theta), sigma_n, 'b-', linewidth=2, label='$\\sigma_n$')
130
ax2.plot(np.degrees(theta), tau_nt, 'r-', linewidth=2, label='$\\tau_{nt}$')
131
ax2.axhline(sigma_1, color='b', linestyle='--', alpha=0.5)
132
ax2.axhline(sigma_2, color='b', linestyle='--', alpha=0.5)
133
ax2.axhline(tau_max, color='r', linestyle='--', alpha=0.5)
134
ax2.axhline(-tau_max, color='r', linestyle='--', alpha=0.5)
135
ax2.axvline(theta_p_deg, color='k', linestyle=':', alpha=0.5)
136
ax2.set_xlabel('Angle $\\theta$ (degrees)')
137
ax2.set_ylabel('Stress (MPa)')
138
ax2.set_title('Stress Transformation')
139
ax2.legend()
140
ax2.grid(True, alpha=0.3)
141
142
plt.tight_layout()
143
save_fig('mohr_circle.pdf')
144
\end{pycode}
145
146
\begin{figure}[H]
147
\centering
148
\includegraphics[width=\textwidth]{mohr_circle.pdf}
149
\caption{Mohr's circle construction and stress transformation with angle.}
150
\end{figure}
151
152
\begin{table}[H]
153
\centering
154
\caption{Principal Stress Results}
155
\begin{tabular}{lcc}
156
\toprule
157
Parameter & Value & Units \\
158
\midrule
159
$\sigma_1$ (max principal) & \py{f"{sigma_1:.1f}"} & MPa \\
160
$\sigma_2$ (min principal) & \py{f"{sigma_2:.1f}"} & MPa \\
161
$\tau_{max}$ & \py{f"{tau_max:.1f}"} & MPa \\
162
Principal angle $\theta_p$ & \py{f"{theta_p_deg:.1f}"} & degrees \\
163
\bottomrule
164
\end{tabular}
165
\end{table}
166
167
\section{3D Stress State and von Mises Stress}
168
169
For a general 3D stress state, the von Mises equivalent stress is:
170
\begin{equation}
171
\sigma_{VM} = \sqrt{\frac{1}{2}[(\sigma_1-\sigma_2)^2 + (\sigma_2-\sigma_3)^2 + (\sigma_3-\sigma_1)^2]}
172
\end{equation}
173
174
For plane stress ($\sigma_3 = 0$):
175
\begin{equation}
176
\sigma_{VM} = \sqrt{\sigma_1^2 - \sigma_1\sigma_2 + \sigma_2^2}
177
\end{equation}
178
179
\begin{pycode}
180
# von Mises stress calculation
181
sigma_3 = 0 # plane stress
182
sigma_VM = np.sqrt(sigma_1**2 - sigma_1*sigma_2 + sigma_2**2)
183
184
# von Mises yield surface (ellipse in sigma_1-sigma_2 space)
185
S_y = 250 # Yield strength (MPa)
186
187
theta_vm = np.linspace(0, 2*np.pi, 200)
188
# Parametric form of von Mises ellipse
189
a = S_y * np.sqrt(2/3)
190
b = S_y * np.sqrt(2)
191
sigma_1_vm = a * np.cos(theta_vm) + b/2 * np.sin(theta_vm)
192
sigma_2_vm = -a * np.cos(theta_vm) + b/2 * np.sin(theta_vm)
193
194
# Tresca yield surface (hexagon)
195
S_tresca = S_y
196
tresca_points = np.array([
197
[S_tresca, 0], [S_tresca, S_tresca], [0, S_tresca],
198
[-S_tresca, 0], [-S_tresca, -S_tresca], [0, -S_tresca], [S_tresca, 0]
199
])
200
201
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
202
203
# von Mises and Tresca yield surfaces
204
ax1.plot(sigma_1_vm, sigma_2_vm, 'b-', linewidth=2, label='von Mises')
205
ax1.plot(tresca_points[:, 0], tresca_points[:, 1], 'r--', linewidth=2, label='Tresca')
206
ax1.plot(sigma_1, sigma_2, 'ko', markersize=10, label=f'Current state')
207
ax1.axhline(0, color='k', linewidth=0.5)
208
ax1.axvline(0, color='k', linewidth=0.5)
209
ax1.set_xlabel('$\\sigma_1$ (MPa)')
210
ax1.set_ylabel('$\\sigma_2$ (MPa)')
211
ax1.set_title('Yield Surfaces (Plane Stress)')
212
ax1.legend()
213
ax1.grid(True, alpha=0.3)
214
ax1.axis('equal')
215
216
# Safety factor visualization
217
SF_VM = S_y / sigma_VM
218
sigma_range = np.linspace(0, S_y, 100)
219
220
# von Mises boundary at various sigma_2/sigma_1 ratios
221
ratios = [-1, -0.5, 0, 0.5, 1]
222
for ratio in ratios:
223
sigma_2_line = ratio * sigma_range
224
sigma_VM_line = np.sqrt(sigma_range**2 - sigma_range*sigma_2_line + sigma_2_line**2)
225
ax2.plot(sigma_range, sigma_VM_line, linewidth=1.5, label=f'$\\sigma_2/\\sigma_1$ = {ratio}')
226
227
ax2.axhline(S_y, color='r', linestyle='--', linewidth=2, label=f'$S_y$ = {S_y} MPa')
228
ax2.plot(sigma_1, sigma_VM, 'ko', markersize=10)
229
ax2.set_xlabel('$\\sigma_1$ (MPa)')
230
ax2.set_ylabel('$\\sigma_{VM}$ (MPa)')
231
ax2.set_title('von Mises Equivalent Stress')
232
ax2.legend(fontsize=8)
233
ax2.grid(True, alpha=0.3)
234
235
plt.tight_layout()
236
save_fig('von_mises.pdf')
237
\end{pycode}
238
239
\begin{figure}[H]
240
\centering
241
\includegraphics[width=\textwidth]{von_mises.pdf}
242
\caption{Yield surfaces and von Mises equivalent stress analysis.}
243
\end{figure}
244
245
von Mises stress: $\sigma_{VM} = \py{f"{sigma_VM:.1f}"}$ MPa, Safety factor = \py{f"{S_y/sigma_VM:.2f}"}
246
247
\section{Failure Theories}
248
249
\begin{pycode}
250
# Comparison of failure theories
251
S_y = 250 # Tensile yield strength
252
S_yc = 300 # Compressive yield strength (for Mohr-Coulomb)
253
S_ut = 400 # Ultimate tensile strength
254
255
# Create principal stress space
256
s1 = np.linspace(-400, 400, 200)
257
s2 = np.linspace(-400, 400, 200)
258
S1, S2 = np.meshgrid(s1, s2)
259
260
# von Mises criterion
261
VM = np.sqrt(S1**2 - S1*S2 + S2**2)
262
263
# Tresca criterion
264
Tresca = np.maximum(np.abs(S1 - S2), np.maximum(np.abs(S1), np.abs(S2)))
265
266
# Rankine (maximum normal stress)
267
Rankine = np.maximum(np.abs(S1), np.abs(S2))
268
269
# Mohr-Coulomb (simplified)
270
MC = np.maximum(S1/S_y - S2/S_yc, S2/S_y - S1/S_yc)
271
272
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
273
274
# von Mises
275
cs1 = axes[0, 0].contour(S1, S2, VM, levels=[S_y], colors='blue', linewidths=2)
276
axes[0, 0].clabel(cs1, fmt='$S_y$=%d' % S_y)
277
axes[0, 0].plot(sigma_1, sigma_2, 'ro', markersize=10)
278
axes[0, 0].axhline(0, color='k', linewidth=0.5)
279
axes[0, 0].axvline(0, color='k', linewidth=0.5)
280
axes[0, 0].set_xlabel('$\\sigma_1$ (MPa)')
281
axes[0, 0].set_ylabel('$\\sigma_2$ (MPa)')
282
axes[0, 0].set_title('von Mises Criterion')
283
axes[0, 0].grid(True, alpha=0.3)
284
axes[0, 0].axis('equal')
285
286
# Tresca
287
cs2 = axes[0, 1].contour(S1, S2, Tresca, levels=[S_y], colors='red', linewidths=2)
288
axes[0, 1].clabel(cs2, fmt='$S_y$=%d' % S_y)
289
axes[0, 1].plot(sigma_1, sigma_2, 'ro', markersize=10)
290
axes[0, 1].axhline(0, color='k', linewidth=0.5)
291
axes[0, 1].axvline(0, color='k', linewidth=0.5)
292
axes[0, 1].set_xlabel('$\\sigma_1$ (MPa)')
293
axes[0, 1].set_ylabel('$\\sigma_2$ (MPa)')
294
axes[0, 1].set_title('Tresca (Max Shear) Criterion')
295
axes[0, 1].grid(True, alpha=0.3)
296
axes[0, 1].axis('equal')
297
298
# Rankine
299
cs3 = axes[1, 0].contour(S1, S2, Rankine, levels=[S_ut], colors='green', linewidths=2)
300
axes[1, 0].clabel(cs3, fmt='$S_{ut}$=%d' % S_ut)
301
axes[1, 0].plot(sigma_1, sigma_2, 'ro', markersize=10)
302
axes[1, 0].axhline(0, color='k', linewidth=0.5)
303
axes[1, 0].axvline(0, color='k', linewidth=0.5)
304
axes[1, 0].set_xlabel('$\\sigma_1$ (MPa)')
305
axes[1, 0].set_ylabel('$\\sigma_2$ (MPa)')
306
axes[1, 0].set_title('Rankine (Max Normal Stress) Criterion')
307
axes[1, 0].grid(True, alpha=0.3)
308
axes[1, 0].axis('equal')
309
310
# Comparison
311
axes[1, 1].contour(S1, S2, VM, levels=[S_y], colors='blue', linewidths=2)
312
axes[1, 1].contour(S1, S2, Tresca, levels=[S_y], colors='red', linewidths=2, linestyles='--')
313
axes[1, 1].plot(sigma_1, sigma_2, 'ko', markersize=10, label='Current state')
314
axes[1, 1].axhline(0, color='k', linewidth=0.5)
315
axes[1, 1].axvline(0, color='k', linewidth=0.5)
316
axes[1, 1].set_xlabel('$\\sigma_1$ (MPa)')
317
axes[1, 1].set_ylabel('$\\sigma_2$ (MPa)')
318
axes[1, 1].set_title('Comparison: von Mises (blue) vs Tresca (red)')
319
axes[1, 1].grid(True, alpha=0.3)
320
axes[1, 1].axis('equal')
321
322
plt.tight_layout()
323
save_fig('failure_theories.pdf')
324
\end{pycode}
325
326
\begin{figure}[H]
327
\centering
328
\includegraphics[width=\textwidth]{failure_theories.pdf}
329
\caption{Comparison of failure theories: von Mises, Tresca, and Rankine.}
330
\end{figure}
331
332
\section{Stress Concentration}
333
334
Stress concentration factors modify nominal stress:
335
\begin{equation}
336
\sigma_{max} = K_t \cdot \sigma_{nom}
337
\end{equation}
338
339
\begin{pycode}
340
# Stress concentration for plate with hole
341
def Kt_plate_hole(d_w):
342
"""Stress concentration factor for plate with central hole under tension"""
343
return 3.0 - 3.14*d_w + 3.667*d_w**2 - 1.527*d_w**3
344
345
d_w_range = np.linspace(0.01, 0.7, 100)
346
Kt = [Kt_plate_hole(dw) for dw in d_w_range]
347
348
# For shaft with fillet
349
def Kt_shaft_fillet(D_d, r_d):
350
"""Approximate Kt for stepped shaft with fillet"""
351
C1 = 0.926 + 1.157*np.sqrt(r_d) - 0.099*r_d
352
C2 = 0.012 - 3.036*np.sqrt(r_d) + 0.961*r_d
353
return C1 + C2*(2*D_d/(D_d+1))
354
355
D_d_values = [1.1, 1.2, 1.5, 2.0]
356
r_d_range = np.linspace(0.01, 0.3, 100)
357
358
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
359
360
# Plate with hole
361
ax1.plot(d_w_range, Kt, 'b-', linewidth=2)
362
ax1.set_xlabel('$d/w$ (hole diameter / plate width)')
363
ax1.set_ylabel('$K_t$')
364
ax1.set_title('Plate with Central Hole')
365
ax1.grid(True, alpha=0.3)
366
367
# Shaft with fillet
368
for D_d in D_d_values:
369
Kt_shaft = [Kt_shaft_fillet(D_d, rd) for rd in r_d_range]
370
ax2.plot(r_d_range, Kt_shaft, linewidth=2, label=f'D/d = {D_d}')
371
372
ax2.set_xlabel('$r/d$ (fillet radius / minor diameter)')
373
ax2.set_ylabel('$K_t$')
374
ax2.set_title('Stepped Shaft with Fillet (Tension)')
375
ax2.legend()
376
ax2.grid(True, alpha=0.3)
377
378
plt.tight_layout()
379
save_fig('stress_concentration.pdf')
380
\end{pycode}
381
382
\begin{figure}[H]
383
\centering
384
\includegraphics[width=\textwidth]{stress_concentration.pdf}
385
\caption{Stress concentration factors for common geometries.}
386
\end{figure}
387
388
\section{Beam Bending Stress}
389
390
\begin{pycode}
391
# Cantilever beam with end load
392
L = 1.0 # m
393
P = 5000 # N
394
b = 0.05 # m (width)
395
h = 0.1 # m (height)
396
I = b * h**3 / 12
397
c = h / 2
398
399
x = np.linspace(0, L, 100)
400
M = P * (L - x) # Moment distribution
401
sigma_max = M * c / I # Maximum bending stress
402
V = P * np.ones_like(x) # Shear force
403
404
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
405
406
# Bending moment diagram
407
axes[0, 0].plot(x, M/1000, 'b-', linewidth=2)
408
axes[0, 0].fill_between(x, 0, M/1000, alpha=0.3)
409
axes[0, 0].set_xlabel('Position (m)')
410
axes[0, 0].set_ylabel('Moment (kN$\\cdot$m)')
411
axes[0, 0].set_title('Bending Moment Diagram')
412
axes[0, 0].grid(True, alpha=0.3)
413
414
# Shear force diagram
415
axes[0, 1].plot(x, V/1000, 'r-', linewidth=2)
416
axes[0, 1].fill_between(x, 0, V/1000, alpha=0.3, color='red')
417
axes[0, 1].set_xlabel('Position (m)')
418
axes[0, 1].set_ylabel('Shear Force (kN)')
419
axes[0, 1].set_title('Shear Force Diagram')
420
axes[0, 1].grid(True, alpha=0.3)
421
422
# Stress distribution through depth at root
423
y = np.linspace(-h/2, h/2, 100)
424
M_root = P * L
425
sigma_y = M_root * y / I
426
427
axes[1, 0].plot(sigma_y/1e6, y*1000, 'g-', linewidth=2)
428
axes[1, 0].axvline(0, color='k', linewidth=0.5)
429
axes[1, 0].axhline(0, color='k', linewidth=0.5)
430
axes[1, 0].set_xlabel('Bending Stress (MPa)')
431
axes[1, 0].set_ylabel('Distance from neutral axis (mm)')
432
axes[1, 0].set_title('Stress Distribution at Root')
433
axes[1, 0].grid(True, alpha=0.3)
434
435
# Maximum stress along beam
436
axes[1, 1].plot(x, sigma_max/1e6, 'm-', linewidth=2)
437
axes[1, 1].set_xlabel('Position (m)')
438
axes[1, 1].set_ylabel('Maximum Bending Stress (MPa)')
439
axes[1, 1].set_title('Maximum Stress Distribution')
440
axes[1, 1].grid(True, alpha=0.3)
441
442
plt.tight_layout()
443
save_fig('beam_bending.pdf')
444
445
sigma_max_root = P * L * c / I
446
\end{pycode}
447
448
\begin{figure}[H]
449
\centering
450
\includegraphics[width=\textwidth]{beam_bending.pdf}
451
\caption{Cantilever beam analysis: moment, shear, and stress distributions.}
452
\end{figure}
453
454
Maximum bending stress at root: $\sigma_{max} = \py{f"{sigma_max_root/1e6:.1f}"}$ MPa
455
456
\section{Conclusions}
457
458
This analysis demonstrates key aspects of stress analysis:
459
\begin{enumerate}
460
\item Mohr's circle provides graphical stress transformation
461
\item Principal stresses define maximum and minimum normal stresses
462
\item von Mises criterion is appropriate for ductile materials
463
\item Tresca is more conservative than von Mises by up to 15\%
464
\item Stress concentration must be considered at geometric discontinuities
465
\item Beam bending produces linear stress distribution through depth
466
\end{enumerate}
467
468
\end{document}
469
470